una tienda seleccionar script hechas hacer ejemplos ejemplo datos creacion consola bases mysql postgresql functional-programming clojure compojure

mysql - tienda - ¿Cómo funciona uno_modelo_ de datos de bases de datos relacionales en clojure?



hacer base de datos en mysql (3)

Esta pregunta no se ha respondido en mucho tiempo, pero Korma http://sqlkorma.com es otro proyecto que también ayuda a reducir la disonancia entre SQL y Clojure. Se ha trabajado más recientemente y debería funcionar con versiones más recientes de Clojure.

He hecho esta pregunta en Twitter, así como en el canal IRC #clojure, pero no obtuve respuestas.

Ha habido varios artículos sobre programadores de Clojure-for-Ruby, programadores de Clojure-for-lisp ... pero lo que falta es Clojure para programadores de ActiveRecord .

Se han publicado artículos sobre la interacción con MongoDB, Redis, etc., pero estos son almacenes de valor clave al final del día. Sin embargo, al tener una formación en Rails, estamos acostumbrados a pensar en las bases de datos en términos de herencia: has_many, polymorphic, corresponde_a, etc.

Los pocos artículos sobre Clojure / Compojure + MySQL ( ffclassic ) - profundizan en sql. Por supuesto, podría ser que un ORM provoque desajuste de impedancia , pero el hecho es que después de pensar como ActiveRecord, es muy difícil pensar de otra manera.

Creo que las bases de datos relacionales se prestan muy bien al paradigma orientado a objetos, ya que esencialmente son conjuntos. Cosas como activerecord son muy adecuadas para modelar estos datos. Por ejemplo, un blog - simplemente poner

class Post < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :post end

¿Cómo se modela esto en Clojure, que es tan estrictamente anti-OO? Quizás la pregunta hubiera sido mejor si se refiriera a todos los lenguajes de programación funcionales, pero estoy más interesado desde el punto de vista de Clojure (y ejemplos de Clojure)


Hay un par de bibliotecas similares a ORM en las obras hoy en día.

En la lista de correo, algunas personas (inteligentes) describieron recientemente algunos otros modelos sobre cómo podría funcionar esto . Cada una de estas bibliotecas adopta un enfoque bastante diferente del problema, así que asegúrese de revisarlas todas.

Aquí hay un ejemplo extendido usando Oyako, por ejemplo. Esta biblioteca no está lista para la producción y todavía está en desarrollo, por lo que el ejemplo puede no ser válido en una semana, pero está llegando. Es una prueba de concepto en cualquier caso. Dale algo de tiempo y alguien tendrá una buena biblioteca.

Tenga en cuenta que clojure.contrib.sql ya le permite obtener registros de una base de datos (a través de JDBC) y terminar con hash-maps inmutables que representan registros. Debido a que los datos terminan en mapas normales, todas las múltiples funciones de Clojure que funcionan en mapas ya funcionan con estos datos.

¿Qué más te da ActiveRecord? Puedo pensar en un par de cosas.

Un DSL de consulta SQL conciso

La forma en que lo modelo mentalmente: Primero, defina la relación entre las tablas. Esto no requiere mutación u objetos. Es una descripción estática. AR distribuye esta información en varias clases, pero la veo como una entidad separada (estática).

Usando las relaciones definidas, puede escribir consultas de una manera muy concisa. Con Oyako por ejemplo:

(def my-data (make-datamap db [:foo [has-one :bar]] [:bar [belongs-to :foo]])) (with-datamap my-data (fetch-all :foo includes :bar))

Luego tendrás algunos objetos foo , cada uno con una tecla :bar que enumera tus barras.

En Oyako, el "mapa de datos" es solo un mapa. La consulta en sí es un mapa. Los datos devueltos son un vector de mapas (de vectores de mapas). Así que terminas con una manera estándar y fácil de construir, manipular e iterar sobre todas estas cosas, lo cual es bueno. Agregue un poco de azúcar (macros y funciones normales), para que pueda crear y manipular de forma concisa estos mapas más fácilmente, y termina siendo bastante poderoso. Esta es solo una forma, hay muchos enfoques.

Si miras una biblioteca como Sequel para otro ejemplo, tienes cosas como:

Artist.order(:name).last

Pero, ¿por qué estas funciones tienen que ser métodos que viven dentro de objetos? Un equivalente en Oyako podría ser:

(last (-> (query :artist) (order :name)))

Guardar / actualizar / borrar registros

Nuevamente, ¿por qué necesita objetos de estilo OO o mutación o herencia de implementación para esto? Primero obtenga el registro (como un mapa inmutable), luego assoc a través de un grupo de funciones, assoc nuevos valores según sea necesario, luego vuelva a introducirlo en la base de datos o elimínelo llamando a una función en él.

Una biblioteca inteligente podría hacer uso de metadatos para realizar un seguimiento de qué campos se han modificado, para reducir la cantidad de consultas necesarias para hacer actualizaciones. O para marcar el registro para que las funciones de DB sepan en qué tabla se debe pegar nuevamente. Carte incluso realiza actualizaciones en cascada (actualización de registros secundarios cuando se modifica un registro principal), creo.

Validaciones, ganchos

Mucho de esto lo veo como perteneciente a la base de datos en lugar de a la biblioteca ORM. Por ejemplo, eliminaciones en cascada (eliminar registros secundarios cuando se eliminan los registros principales): AR tiene una manera de hacer esto, pero puede simplemente lanzar una cláusula en la tabla en el DB y luego dejar que su DB lo maneje, y nunca más volver a preocuparse. Lo mismo con muchos tipos de restricciones y validaciones.

Pero si desea ganchos, pueden implementarse de una manera muy liviana utilizando funciones o métodos múltiples de uso simple. En algún momento en el pasado tuve una biblioteca de base de datos que llamaba ganchos en diferentes momentos del ciclo de CRUD, por ejemplo, after-save o before-delete . Eran simples métodos múltiples de despacho sobre nombres de tablas. Esto te permite extenderlos a tus propias tablas como quieras.

(defmulti before-delete (fn [x] (table-for x))) (defmethod before-delete :default [& _]) ;; do nothing (defn delete [x] (when (before-delete x) (db-delete! x) (after-delete x)))

Luego, más tarde, como usuario final, podría escribir:

(defmethod before-delete ::my_table [x] (if (= (:id x) 1) (throw (Exception. "OH NO! ABORT!")) x))

Fácil y extensible, y tomó un par de segundos para escribir. No hay OO a la vista. No es tan sofisticado como AR, pero a veces simple es lo suficientemente bueno.

Mira esta biblioteca para otro ejemplo de definición de ganchos.

Migraciones

Carte tiene estos. No he pensado mucho en ellos, pero la versión de una base de datos y la recopilación de datos en ella no parecen estar fuera del alcance de Clojure.

polaco

Gran parte de lo bueno de AR proviene de todas las convenciones para nombrar tablas y nombrar columnas, y de todas las funciones de conveniencia para poner mayúsculas en las palabras y formatear fechas y demás. Esto no tiene nada que ver con OO vs. non-OO; AR solo tiene mucho pulimento porque se le ha dedicado mucho tiempo. Tal vez Clojure aún no tenga una biblioteca de clase AR para trabajar con datos de base de datos, pero dale algo de tiempo.

Asi que...

En lugar de tener un objeto que sabe cómo destruirse, mutarse, guardarse, relacionarse con otros datos, buscarse, etc., en lugar de eso solo tiene datos, y luego define funciones que funcionan con esos datos: guarda lo destruye, lo actualiza en el DB, lo recupera, lo relaciona con otros datos. Así es como Clojure funciona con los datos en general, y los datos de una base de datos no son diferentes.

Foo.find(1).update_attributes(:bar => "quux").save! => (with-db (-> (fetch-one :foo :where {:id 1}) (assoc :bar "quux") (save!))) Foo.create!(:id => 1) => (with-db (save (in-table :foo {:id 1})))

Algo como eso. Se trata de la forma en que funcionan los objetos, pero proporciona la misma funcionalidad. Pero en Clojure, también obtiene todos los beneficios de escribir código de una manera FP.


Se ha iniciado un nuevo DSL de micro SQL basado en clojure.contrib.sql. Está en Github con un peso de 76 loc.

Hay muchos ejemplos y teorías detrás del DSL en el blog del autor, vinculados a su perfil de Github (nuevo usuario, SO hipervínculo limit bah). Su diseño permite que el SQL se abstraiga en un Clojure mucho más idiomático, me parece.