2015-08-05 2 views
2

Je travaille avec datomic.api de clojure. Je souhaite refactoriser une requête datalog quelque peu complexe comme ceci:Définition de composants de requête datalog en dehors de (datomic.api/q '[])

(datomic.api/q '[:find [?value ...] :in $ ?uid ?component :where 
       [...some clause...] 
       [...some other clause...] 
       (or-join [?entitlement ?component] 
         (and [...some conditional stuff...]) 
         (and [...some other conditional stuff...]))] 
       db uid component) 

... en quelque chose de plus lisible. Mon souhait est de lier localement les composants (and...) de la requête à l'intérieur d'un let et de s'y référer par un nom à l'intérieur de la liste des données. Comme si:

(datomic.api/q '[:find [?value ...] :in $ ?uid ?component :where 
       [...some clause...] 
       [...some other clause...] 
       (or-join [?entitlement ?component] 
         entitled-for-component 
         entitled-for-application)] 
       db uid component) 

Divers citant dans let (et unquoting à l'intérieur de la liste datomic.api/q) n'ont pas travaillé. Aucune suggestion?

+0

Oui. L'approche de type citant/désapproprie fonctionne si vous utilisez des guillemets de syntaxe, mais vous finirez avec des éléments comme * et * remplacés par des symboles qualifiés d'espace de noms, ce qui va le casser de façon différente. Votre réponse ci-dessous est la façon de s'y prendre. –

+0

J'aime la réponse ci-dessous, pour utiliser les règles. Pour quasiquote dans Clojure comme vous le feriez dans d'autres lisps, essayez le formulaire 'template' dans [backtick] (https://github.com/brandonbloom/backtick). –

Répondre

2

Datomic utilise rules pour résoudre ce problème. Datomic datalog vous permet d'empaqueter des ensembles de: where clauses en règles nommées. Ces règles rendent la logique de requête réutilisable, ainsi que composable, ce qui signifie que vous pouvez lier des parties de la logique d'une requête au temps de requête . Les ensembles de règles sont définis comme une liste de listes, puis utilisés comme une entrée supplémentaire avec datomic.api/q lié au caractère%.

(def rules [[(name-for-id restaurant-id?) 
      [restaurant-id? :restaurant/name name?]]]) 

(datomic.api/q '[:find ?name . :in $ % ?restaurant-id :where 
       (name-for-id restaurant-id?)] db rules 42) 

=> "Milliways" 

Notez que datomic.api/q une règle attend mis, en passant une seule règle ne fonctionnera pas.

La première liste d'une règle définit le nom de la règle en tant que premier élément, suivi par un ou plusieurs paramètres. Les vecteurs suivants contiennent une ou plusieurs: where clauses.

En outre,

Comme avec d'autres clauses où, vous pouvez spécifier une base de données avant que la règle nom à la portée la règle à cette base de données. Les bases de données ne peuvent pas être utilisées comme arguments dans une règle.