ORM pour clojure?

Je lisais ce site sur la pile web clojure:

Http://brehaut.net/blog/2011/ring_introduction

Et il a ceci à dire à propos D'ORM pour clojure:

"Il n'y a pas D'ORM SQL/DB relationnel pour Clojure pour des raisons évidentes."

La raison évidente que je peux voir est que le mappage à l'objet se produit automatiquement lorsque vous faites un clojure.contrib.requête sql ou clojureql. Cependant, il semble un travail supplémentaire est nécessaire pour faire un-à-plusieurs ou plusieurs-à-plusieurs relations (bien que peut-être pas trop de travail).

J'ai trouvé cette écriture pour l'un-à-plusieurs: http://briancarper.net/blog/493/

Avec lequel je ne suis pas sûr d'être d'accord; il semble supposer que les deux tables sont extraites de la base de données et que la table jointe est filtrée en mémoire. En pratique, je pense que la requête sql spécifierait les critères where.

Donc, je me demande s'il existe un moyen assez évident de faire automatiquement des relations one-to-many via clojureql ou clojure.contrib.sql? La seule chose à laquelle je peux penser est quelque chose comme ceci (en utilisant l'exemple typique de blog / commentaire):

(defn post [id] 
    @(-> (table :posts)
        (select (where :id id))))
(defn comments [post_id]
    @(-> (table :comments) 
         (select (where :post_id post_id))))
(defn post-and-comments [id]
    (assoc (post id) :comments (comments id)))

Est - il possible d'automatiser ce concept ou est-ce aussi bon que possible?

37
demandé sur Kevin 2011-09-08 21:09:39

8 réponses

Il n'y a toujours pas de bibliothèque de haut niveau pour créer des requêtes relationnelles complexes que je connais. Il y a plusieurs façons de résoudre ce problème (le lien que vous avez fourni est un moyen) mais même si ClojureQL fournit un DSL très agréable sur lequel vous pouvez construire, il manque encore quelques fonctionnalités importantes. Voici un exemple rapide et sale d'une macro qui génère des jointures imbriquées:

(defn parent-id [parent]
  (let [id (str (apply str (butlast (name parent))) "_id")]
    (keyword (str (name parent) "." id))))

(defn child-id [parent child]
  (let [parent (apply str (butlast (name parent)))]
    (keyword (str (name child) "."  parent "_id"))))

(defn join-on [query parent child]
  `(join ~(or query `(table ~parent)) (table ~child)
         (where
          (~'= ~(parent-id parent)
               ~(child-id parent child)))))

(defn zip [a b] (map #(vector %1 %2) a b))

(defmacro include [parent & tables]
  (let [pairs (zip (conj tables parent) tables)]
    (reduce (fn [query [parent child]] (join-on query parent child)) nil pairs)))

Avec cela, vous pouvez faire (include :users :posts :comments) et en sortir ce SQL:

SELECT users.*,posts.*,comments.*
  FROM users
  JOIN posts ON (users.user_id = posts.user_id)
  JOIN comments ON (posts.post_id = comments.post_id)

Il y a un problème majeur avec cette technique bien. Le problème principal est que les colonnes renvoyées pour toutes les tables seront regroupées dans la même carte. Comme les noms de colonnes ne peuvent pas être qualifiés automatiquement, cela ne fonctionnera pas s'il y a une colonne nommée de la même manière dans différentes tables. Cela vous empêchera également de regrouper les résultats sans avoir accès au schéma. Je ne pense pas qu'il y ait un moyen de contourner le schéma de base de données pour ce genre de choses, donc il y a encore beaucoup de travail à faire. Je pense que ClojureQL restera toujours un bibliothèque de bas niveau, vous devrez donc attendre qu'une autre bibliothèque de niveau supérieur existe ou crée la vôtre.

Pour créer une telle bibliothèque, vous pouvez toujours consulter la classe DatabaseMetaData de JDBC pour fournir des informations sur le schéma de base de données. Je travaille toujours sur un analyseur de base de données pour Lobos qui l'utilise (et quelques trucs personnalisés) mais je suis encore loin de commencer à travailler sur des requêtes SQL, que je pourrais ajouter dans la version 2.0.

10
répondu Nicolas Buduroi 2011-09-16 07:35:08

J'ai posé cette question il y a un moment, mais j'ai rencontré ce qui suit et j'ai décidé de l'ajouter comme réponse au cas où quelqu'un serait intéressé:

Http://sqlkorma.com/

28
répondu Kevin 2012-01-22 18:31:25

La raison "évidente" pour laquelle vous n'avez pas besoin D'ORM en tant que tel dans Clojure est que Clojure idiomatique n'a pas d'objets, en soi.

La meilleure façon de représenter les données dans un programme Clojure est de SEQ paresseux de strutures de données simples (cartes et vecteurs). Le mappage de ces lignes SQL est beaucoup moins complexe et présente beaucoup moins d'impédance que L'ORM complet.

Aussi, en ce qui concerne la partie de votre question relative à la formation d'une requête SQL complexe... en lisant votre code, il n'a pas vraiment tous les avantages clairs sur SQL lui-même. N'ayez pas peur de SQL! C'est génial pour ce qu'il fait: la manipulation de données relationnelles.

25
répondu levand 2011-09-17 23:16:12

Au risque de nager dans les eaux avec certains des frappeurs si lourds (pour mélanger mes métaphores, à fond ;) - sûrement l'une des meilleures caractéristiques D'ORM est que, pour la grande majorité des cas, le programmeur pragmatique doit Jamais utiliser ou même penser à SQL. Au pire, une programmation hacky avec les résultats de quelques requêtes peut être nécessaire, sur la base que cela sera converti en SQL brut lorsque cette optimisation est nécessaire, bien sûr,;).

Pour dire QU'ORM est pas nécessaire pour la raison "évidente", manque quelque peu le point. En outre, commencer à utiliser un DSL pour modéliser SQL aggrave cette erreur. Dans la grande majorité des frameworks web, le modèle d'objet est DSL utilisé pour décrire les données stockées par l'application web et SQL simplement le langage déclaratif tenus de communiquer à la base de données.

Ordre des étapes lors de L'utilisation de ROR, django ou Spring:

  1. décrivez vos modèles dans un format POO
  2. ouvrir REPL et faire quelques exemples de modèles
  3. construire des vues
  4. vérifier les résultats dans le navigateur web

Ok, donc vous pouvez utiliser un ordre légèrement différent, mais j'espère que vous obtenez le point. Penser en SQL ou un DSL qui le décrit est loin dans la liste. Au lieu de cela, la couche modèle élimine tout le SQL, ce qui nous permet de créer des objets de données qui modélisent étroitement les données que nous souhaitons utiliser dans le site web.

Je suis tout à fait d'accord que la POO n'est pas une solution miracle, cependant, modéliser des données dans un framework web est quelque chose pour lequel il est certainement bon, et exploiter la capacité de clojure à définir et à manipuler des classes Java semblerait être un bon match ici.

Les exemples de la question démontrent clairement à quel point SQL peut être douloureux, et les DSL comme Korma ne sont qu'une solution partielle: "supposons que nous ayons des tables dans une base de données..."- euh, je pensais que mon DSL allait créer ceux pour moi? Ou est-ce juste quelque chose qu'un langage POO fait mieux? ;)

6
répondu Henry Florence 2013-11-13 08:54:47

Avez-vous vérifié la bibliothèque Korma http://sqlkorma.com/? Il vous permet de définir des relations de table et d'abstraire les jointures. Je pense qu'une raison majeure pour laquelle il n'y a pas D'ORM pour clojure est parce qu'ils vont à l'encontre des idées de simplicité de Rich Hickey sur lesquelles la langue a été fondée. Consultez cette présentation: http://www.infoq.com/presentations/Simple-Made-Easy

4
répondu Sean Geoffrey Pietz 2014-01-25 15:10:44

La bibliothèque appeléeaggregate peut prendre en charge la plupart des démangeaisons que vous avez ici. Ce N'est pas un ORM à grande échelle, mais si vous lui indiquez le graphique de relation pour votre schéma de base de données, il fournit des implémentations CRUD qui parcourent automatiquement le graphique de relation. C'est utile si vous utilisez déjà quelque chose comme yesql ou des requêtes SQL brutes, car il se branche facilement à une implémentation qui utilise des cartes de résultats simples.

1
répondu amoe 2016-03-08 12:41:02

Que vous souhaitiez les utiliser ou non, il y avait déjà aggregate et il y a toucan maintenant (et ils ont apparemment lu le même lien que vous l'avez fait).

0
répondu nha 2017-09-27 23:22:21

ORM est une optimisation prématurée. Walkable est la nouvelle bibliothèque sql pour Clojure qui adopte une approche holistique. Vérifiez-le ici https://github.com/walkable-server/walkable .

Un exemple du monde réel pour ceux qui sont sceptiques de readmes de fantaisie: https://github.com/walkable-server/realworld

0
répondu myguidingstar 2018-05-04 12:02:52