Using Macros in Clojure

I'm specifically trying to generate a template for crud functions to work with the Google App Engine datastore using appengine-magic in Clojure. It’s hard for me to understand how to create values ​​from the model that I reproduced below.

(def *model* {:users [{:name "Adam" :email " adam@gmail.com " :registered-on "07-05-2011"} {:name "Greg" :email " gregory@gmail.com " :registered-on "11-05-2011"}] :post [{:title "A" :authour "Adam"} {:title "B" :author "Greg"}]}) 

I am new to appengine-magic, but it provides a succession that allows you to define objects that you can put in the data warehouse and save! which allows you to store predefined objects in the data warehouse.

They have the form:

 (ds/defentity Post [title author]) (ds/save! (Post. title author)) 

Now, just for starters, I defined:

 (defn list-entities [model] "Takes a representation of the model and lists the entities in preparation for generating defentities" (interleave (vec (map first (partition 1 (map (comp symbol capitalize #(str % ".") name) (keys model))))) (map vec (map keys (map first (vals model)))))) 

Call using:

 (list-entities *model*) 

Outputs:

 (Users. [:name :email :registered-on] Post. [:title :author]) 

Now I am having difficulty defining gen entities that will output the above result and re-call ds / defentities that define as many objects as my model needs.

 (defmacro gen-entities [entity fields] `(ds/defentity 'entity 'fields)) 

In addition, I am in no way sure that this is a reasonable way to solve this problem. I'm still very new to macros and probably made some mistakes. Any help / clarity would be appreciated.

Note:

This model, which I understood, is poorly designed, one of them is much better:

 (def *model* {:users [:name :email :registered-on] :post [:title :author]}) 

However, it’s more difficult to write a macro, so I’ll leave it as it is.

+6
source share
1 answer

I think a macro is required because defentity seems to define the type.

 (defmacro gen-entities [model] `(do ~@ (for [[entity-kw values] model] (let [entity-sym (-> entity-kw name capitalize symbol) fields (map (comp symbol name) (keys (first values)))] `(ds/defentity ~entity-sym [ ~@fields ]))))) 

You don't have to bother with keys and values ​​apart, just to combine them with alternation again. Map matching will give you the key and the corresponding value at a time.

 user=> (macroexpand-1 `(gen-entities ~model)) (do (ds/defentity Users [name registered-on email]) (ds/defentity Post [title authour])) 

Note: this will not work with the model stored in Var. You must specify the model in the gen-entities call.

 user=> (macroexpand-1 '(gen-entities model)) ( #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol> 
+1
source

Source: https://habr.com/ru/post/887536/


All Articles