1. Shantanu Kumar
  2. SQLRat

Commits

shantanuk  committed dca9318

doumentation for entity.clj
change signature of find-siblings: change argument rel-entity to rel-entity-type

  • Participants
  • Parent commits 754835b
  • Branches default

Comments (0)

Files changed (2)

File src/main/clj/org/bituf/sqlrat/entity.clj

View file
  • Ignore whitespace
   "Create one-to-many relation metadata.
   Arguments: See 'relation' function
   Example:
-    TODO
-  See also: relation"
+    (one-to-many :orderid item-metadata :itemid)
+  See also: relation, many-to-one"
   [^Keyword this-col ^EntityMetadata that-ent-meta ^Keyword that-col]
   (relation this-col that-ent-meta that-col true))
 
   "Create many-to-one relation metadata.
   Arguments: See 'relation' function
   Example:
-    TODO
-  See also: relation"
+    (many-to-one :itemid order-metadata :orderid)
+  See also: relation, one-to-many"
   [^Keyword this-col ^EntityMetadata that-ent-meta ^Keyword that-col]
   (relation this-col that-ent-meta that-col false))
 
 
 
 (defn find-by-sql
-  "Find entities with custom SQL/criteria. This is a free-form style. 'f' is
-  a function that accepts result entities as an argument and must not return
-  something that lazily processes the entities.
-  TODO"
+  "Find entities with custom SQL/criteria (in the same format as required by
+  clojure.contrib.sql). When you do not pass a function as the first argument
+  it retrieves all rows from the result set and returns a vector of entities.
+  Arguments:
+    f       (Function) that accepts result entities as the only argument and
+            must not return something that lazily processes the entities.
+    sql-vec (Vector) SQL vector in the format [\"SELECT * FROM e WHERE id=?\" 5]
+  Example:
+    (in-db mysql
+      (println
+        (find-by-sql employee-meta [\"SELECT * FROM emp\"])))
+  See also: with-find-by-sql-results"
   ([^IFn f ^EntityMetadata entity-meta ^IPersistentVector sql-vec]
     (if *assert-args* (do
                         (assert (fn? f))
       (find-by-sql f entity-meta sql-vec))))
 
 
-(defmacro with-find-by-sql-results "Wrapper macro for find-by-sql"
+(defmacro with-find-by-sql-results
+  "Wrapper macro for find-by-sql. You must not return something that processes
+  the result lazily.
+  Arguments:
+    entities     (Symbol) that is bound to the entities returned by the query 
+    entity-meta  Metadata for the entity type being fetched
+    sql-vec      (Vector) the SQL expression
+    body         Function body to work on the entities
+  Example:
+    (in-db mysql
+      (with-find-by-sql-results es emp-meta [\"SELECT * FROM emp\"]
+        (println es)))
+  See also: find-by-sql"
   [entities ^EntityMetadata entity-meta ^IPersistentVector sql-vec & body]
   `(find-by-sql (fn [~entities] ~@body) ~entity-meta ~sql-vec))
 
 
 (defn find-by-criteria
   "Find entities using :cols, :where, :groupby and :other attributes and return
-  a lazy sequence. Examples are below:
-  :cols [:title :content \"whenposted\"]
-  :where [\"whenposted < ?\" (new java.util.Date)]
-  >> OR >> :where (<? :whenposted (new java.util.Date))
-  :other [\"ORDER BY whenposted\"]
-  >> OR >> :other (merge-key-clause :order-by (cscols [:whenposted]))
-  'f' accepts entities as the only argument and must not return something that
-  processes the entities lazily.
-  TODO"
+  a lazy sequence. If the first argument is not a function, it builds entities
+  from the entire result set and returns them in a vector.
+  Arguments:
+    f             (Function) receives lazy-seq of entities as the only argument
+                  and must not return something that processes them lazily.
+    entity-meta   Metadata for the entity type
+  Optional arguments (Criteria):
+    :cols    <v>  (Vector) of column names (or clauses)
+    :where   <v>  (Clause)
+    :groupby <v>  (Vector) of expressions to group by
+    :other   <v>  (Clause)
+  Examples:
+    (in-db mysql
+      (println
+        (find-by-criteria emp-meta {:where [\"salary>?\" 10000]} )))
+  Examples of optional args:
+    :cols  [:title :content \"whenposted\"]
+    :where [\"whenposted < ?\" (new java.util.Date)]
+    | OR | :where (<? :whenposted (new java.util.Date)) ; clause
+    :other [\"ORDER BY whenposted\"]
+    | OR | :other (merge-key-clause :order-by (cscols [:whenposted])) ; clause
+  See also: with-find-by-criteria-results"
   ([^IFn f ^EntityMetadata entity-meta
     ^IPersistentMap {:keys [^IPersistentVector cols    ^IPersistentVector where
                             ^IPersistentVector groupby ^IPersistentVector other]
 
 
 (defmacro with-find-by-criteria-results
+  "Wrapper macro for find-by-criteria. You must not return something that
+  processes the result lazily.
+  Arguments:
+    entities     (Symbol) that is bound to the entities returned by the query 
+    entity-meta  Metadata for the entity type being fetched
+    criteria     (Map) of optional criteria arguments (see find-by-criteria fn)
+    body         Function body to work on the entities
+  Example:
+    (in-db mysql
+      (with-find-by-criteria-results es emp-meta {:cols [:name :code]
+                                                  :where [\"salary>?\" 10000]}
+        (println es)))
+  See also: find-by-criteria"
   [entities ^EntityMetadata entity-meta ^IPersistentMap criteria & body]
   `(let [{cols# :cols where# :where groupby# :groupby other# :other} ~criteria]
     (find-by-criteria (fn [~entities] ~@body) ~entity-meta
 
 
 (defn find-by-id
-  "Find an entity of given type for a given ID. You can also pass :cols, :where,
-  :groupby and :other attributes as in 'find-by-criteria' function.
-  TODO"
-  [^EntityMetadata entity-meta id &
-   ^IPersistentMap {:keys [^IPersistentVector cols    ^IPersistentVector where
-                           ^IPersistentVector groupby ^IPersistentVector other]
-                    :or   {cols    [star-col]     ;; vector of col names
-                           where   (empty-clause) ;; clause
-                           groupby []             ;; vector of expressions
-                           other   (empty-clause) ;; clause
-                           }}]
-  (if *assert-args* (do
-                      (assert-as entity-meta EntityMetadata)
-                      (assert (not (nil? id)))
-                      (assert-criteria {:cols    cols    :where where
-                                        :groupby groupby :other other})))
-  (let [id-clause    (=? (:id entity-meta) id)
-        where-clause (if (empty-clause? where) id-clause
-                       (AND id-clause where))
-        rows         (find-by-criteria entity-meta
-                       {:cols    cols    :where   where-clause
-                        :groupby groupby :other   other} )]
-    (if (empty? rows) nil
-      ((:from-row-fn entity-meta) (first rows)))))
+  "Find an entity of given type using specified ID. You can also pass :cols,
+  :where, :groupby and :other attributes as in 'find-by-criteria' function.
+  Arguments:
+    entity-meta  Metadata for the entity type
+    criteria     (Map) Optional arguments as described in find-by-criteria
+  Example:
+    (in-db mysql
+      (println (find-by-idemp-meta 1197)))
+  See also: find-by-criteria"
+  ([^EntityMetadata entity-meta id
+    ^IPersistentMap {:keys [^IPersistentVector cols    ^IPersistentVector where
+                            ^IPersistentVector groupby ^IPersistentVector other]
+                     :or   {cols    [star-col]     ;; vector of col names
+                            where   (empty-clause) ;; clause
+                            groupby []             ;; vector of expressions
+                            other   (empty-clause) ;; clause
+                            }}]
+    (if *assert-args* (do
+                        (assert-as entity-meta EntityMetadata)
+                        (assert (not (nil? id)))
+                        (assert-criteria {:cols    cols    :where where
+                                          :groupby groupby :other other})))
+    (let [id-clause    (=? (:id entity-meta) id)
+          where-clause (if (empty-clause? where) id-clause
+                         (AND id-clause where))
+          rows         (find-by-criteria entity-meta
+                         {:cols    cols    :where   where-clause
+                          :groupby groupby :other   other} )]
+      (if (empty? rows) nil
+        ((:from-row-fn entity-meta) (first rows)))))
+  ([^EntityMetadata entity-meta id]
+    (find-by-id entity-meta id {})))
 
 
 (defn save
-  "Save given entity"
+  "Save given entity
+  Example:
+    (in-txn mysql
+      (let [e (Employee. {} {:name \"Billy Norman\" :code 5564})]
+        (save e)))
+  See also: find-by-id"
   [^Entity entity]
   (if *assert-args* (assert-arg entity? entity))
   (let [ent-meta (get-meta entity)
   "Delete entity. Variants:
   [entity-meta id] >> delete by ID
   [entity] >> delete given entity
-  TODO"
+  See also: find-by-id"
   ([entity-meta id]
     (if *assert-args* (assert-as entity-meta EntityMetadata))
     (sql/delete-rows (:name entity-meta)
   [e1r1 e1r2 e2r1 e2r2 e2r3] as related entities, and you get back
   {e1 [e1r1 e1r2]
    e2 [e2r1 e2r2 e2r3]}
-  Note: e3 is not a key in the map as it has no corresponding related entities
-  TODO"
+  Note: e3 is not a key in the map as it has no corresponding related entities"
   [^IPersistentVector entities ^IPersistentVector rel-entities]
   (if *assert-args* (do
                       (assert-same-type-entities entities)
 (defn find-rels
   "Fetch related entities. You can use the :cols, :where, :groupby and :other
   attributes as in find-by-criteria function. This avoids N+1 Selects. Return
-  a sequence of entity:child pairs. 'f' is a function that takes one argument
+  a sequence of related entities. 'f' is a function that takes one argument
   (the sequence) and must not return something that processes the arg lazily.
-  TODO"
+  Arguments:
+    f          (Function) that accepts only one argument (entities) and must not
+               return something that processes them lazily.
+    entities   (Vector) of entities to find related entities for
+    that-meta  (EntityMetadata) related entity
+  Optional arguments: See find-by-criteria
+  Example:
+    (in-db mysql
+      (let [es (find-by-criteria order-meta
+                 {:where (=? :orderdt (java.util.Date.))} ) ; orders today
+            rs (find-rels es order-line-meta {:where (>? :qty 5)})] ; qty > 5
+        (println rs)))
+  See also: with-find-rels-results"
   ([^IFn f ^IPersistentVector entities ^EntityMetadata that-meta
     ^IPersistentMap {:keys [^IPersistentVector cols    ^IPersistentVector where
                             ^IPersistentVector groupby ^IPersistentVector other]
 
 
 (defmacro with-find-rels-results
-  "TODO"
+  "Wrapper macro for find-rels. You must not return something that processes
+  the result lazily.
+  Arguments:
+    rel-entities (Symbol) that is bound to the entities returned by the query
+    entities     (Vector) of entities for which related entities to be fetched 
+    that-meta    (EntityMetadata) for the related entity type
+    criteria     (Map) of optional criteria arguments (see find-by-criteria fn)
+    body         Function body to work on the result
+  Example:
+    (in-db mysql
+      (let [es (find-by-criteria order-meta
+                 {:where (=? :orderdt (java.util.Date.))} ) ; orders today]
+        (with-find-rels-results rs es order-line-meta {:where (>? :qty 5)}
+          (println rs))))
+  See also: find-rels"
   [rel-entities ^IPersistentVector entities ^EntityMetadata that-meta
    ^IPersistentMap criteria & body]
   `(let [{cols# :cols where# :where groupby# :groupby other# :other} ~criteria]
 (defn find-entity-rels-map
   "Find related entities for the given set of entities and return a map of
   entity versus related-entities (see entity-rel-map function for details).
-  TODO"
+  See also: entity-rel-map, find-rels"
   ([^IPersistentVector entities ^EntityMetadata that-meta
     ^IPersistentMap criteria]
     (entity-rels-map entities (find-rels entities that-meta criteria)))
     (find-entity-rels-map entities that-meta {})))
 
 
-(defn save-deps [^Entity entity ^IPersistentVector dep-entities]
-  "Save dependents (THAT table) -- 1-to-many (has-many) relationships
-  TODO"
+(defn save-deps
+  "Save dependents (dep-entities) in a 1-to-many scenario for a given entity."
+  [^Entity entity ^IPersistentVector dep-entities]
   (if *assert-args* (do
                       (assert (map? entity))
                       (assert (vector? dep-entities))
 
 
 (defn find-siblings
-  "Fetch sibling entities - Many-to-1 relationships. You can use the :cols,
+  "Fetch sibling entities in a Many-to-1 scenario. You can use the :cols,
   :where, :groupby and :other attributes as in find-by-criteria function.
-  TODO"
-  ([^IFn f ^Entity entity ^Entity rel-entity
+  'entity' has a many-to-1 relation with 'rel-entity' here and siblings of
+  'entity' are fetched with respect to 'rel-entity'. Unless you mention in the
+  criteria, the argument entity is also included in the result.
+  Arguments:
+    f                (Function) that accepts only one argument, i.e. entities
+                     and must not return something that processes them lazily
+    entity           (Entity) - 'Many' side of Many-to-1 scenario
+    rel-entity-meta  (EntityMetadata) - '1' side of Many-to-1 scenario
+    criteria         (Map) optional attributes as described in find-by-criteria
+  Example:
+    (in-db mysql
+      (let [e (find-by-id employee-meta 446)
+            r (find-siblings e department-meta)]
+        (println r)))
+  See also: with-find-siblings-results"
+  ([^IFn f ^Entity entity ^EntityMetadata rel-entity-meta
     ^IPersistentMap {:keys [cols where groupby other]
                      :or   {cols    [star-col]     ;; vector of col names
                             where   (empty-clause) ;; clause
     (if *assert-args* (do
                         (assert (fn? f))
                         (assert (map? entity))
-                        (assert (map? rel-entity))
+                        (assert-as rel-entity-meta EntityMetadata)
                         (assert-criteria {:cols    cols    :where where
                                           :groupby groupby :other other})))
     (let [this-meta       (get-meta entity)
           that-table-map  (dbrel-lookup-by-that-entity (rel-meta entity))
-          rel-data        (that-table-map (:name (get-meta rel-entity)))
+          rel-data        (that-table-map (:name rel-entity-meta))
           this-table-name (name (:name this-meta))
           this-col-name   (name (:this-column rel-data))
-          that-id-value   ((:that-column rel-data) rel-entity)
+          ;that-id-value   ((:that-column rel-data) rel-entity)
+          this-col-value  ((:this-column rel-data) entity)
+          ;_               (assert (= this-col-valu that-id-value))
           ;; add 'this-col = that-id-value' expression to the WHERE clause
           old-where    (as-clause where)
-          new-where    (=? this-col-name that-id-value)
+          new-where    (=? this-col-name this-col-value)
           where-clause (if (empty-clause? old-where) new-where
                          (AND new-where old-where))
           criteria     {:cols    cols    :where where-clause
           ]
       (with-find-by-criteria-results ents this-meta criteria
         (f ents))))
-  ([^Entity entity ^Entity rel-entity ^IPersistentMap criteria]
-    (find-siblings #(into [] %) entity rel-entity criteria))
-  ([^Entity entity ^Entity rel-entity]
-    (find-siblings #(into [] %) entity rel-entity {})))
+  ([^Entity entity ^EntityMetadata rel-entity-meta ^IPersistentMap criteria]
+    (find-siblings #(into [] %) entity rel-entity-meta criteria))
+  ([^Entity entity ^EntityMetadata rel-entity-meta]
+    (find-siblings #(into [] %) entity rel-entity-meta {})))
 
 
 (defmacro with-find-siblings-results
-  "TODO"
-  [sibling-entities ^Entity entity ^Entity rel-entity ^IPersistentMap criteria
-   & body]
-  `(find-siblings (fn [~sibling-entities] ~@body) ~entity ~rel-entity
+  "Wrapper macro for find-siblings. You must not return something that processes
+  the result lazily.
+  Arguments:
+    sibling-entities (Symbol) that is bound to the entities returned by the query
+    entity           (Entity) for which sibling entities to be fetched 
+    rel-entity-meta  (EntityMetadata) for the related entity type
+    criteria         (Map) of optional criteria arguments (see find-by-criteria)
+    body             Function body to work on the result
+  Example:
+    (in-db mysql
+      (let [e (find-by-id employee-meta 446)]
+        (with-find-siblings-results sib e department-meta {}
+          (println sib))))
+  See also: find-rels"
+  [sibling-entities ^Entity entity ^EntityMetadata rel-entity-meta
+   ^IPersistentMap criteria & body]
+  `(find-siblings (fn [~sibling-entities] ~@body) ~entity ~rel-entity-meta
      ~criteria))
 
 
 (defn delete-cascade
-  "Delete (cascaded) a given entity"
+  "Delete a given entity (cascaded, i.e. also deep-delete dependent relations)"
   [^Entity entity]
   (if *assert-args* (assert-arg entity? entity))
   (let [rels (rel-meta entity)]
 (defn print-entities
   "Print homogenous entities in a table format. Keys from the first entity are
   used as title. Passing an empty sequence of entities prints nothing at all.
-  TODO"
+  Arguments:
+    entities  (Vector) of entities"
   [^IPersistentVector entities]
   (mypp "\nENTITIES ***\n" entities)
   (if *assert-args*

File src/test/clj/org/bituf/sqlrat/test/dbblog.clj

View file
  • Ignore whitespace
       (let [e (find-by-id blog-entry-meta 2)
             r ((find-entity-rels-map [e] entry-comment-meta) e)
             c (first r)
-            s (find-siblings c e)
-            sc (find-siblings c e {:cols  [:content :name :email]})
-            sw (find-siblings c e {:where (as-clause ["name LIKE ?" "Phi%"])})
-            sb (find-siblings c e {:cols  [:content :name :email]
-                                   :where (as-clause ["name LIKE ?" "Phi%"])})]
+            s (find-siblings c (get-meta e))
+            sc (find-siblings c (get-meta e) {:cols  [:content :name :email]})
+            sw (find-siblings c (get-meta e) {:where (as-clause
+                                                       ["name LIKE ?" "Phi%"])})
+            sb (find-siblings c (get-meta e) {:cols  [:content :name :email]
+                                              :where (as-clause
+                                                       ["name LIKE ?" "Phi%"])})]
         (is (= 2 (count s)))
         (is (= 3 (count (keys (first sc)))))
         (is (= 1 (count sw)))
             e  (find-by-id blog-entry-meta 2)
             r2 ((find-entity-rels-map [e] entry-comment-meta {:cols [count-col]}) e)
             c  (first r2)
-            s  (find-siblings c e {:cols [count-col]})
-            sw (find-siblings c e {:cols  [count-col]
-                                   :where (as-clause ["name LIKE ?" "Phi%"])})]
+            s  (find-siblings c (get-meta e) {:cols [count-col]})
+            sw (find-siblings c (get-meta e) {:cols  [count-col]
+                                              :where (as-clause
+                                                       ["name LIKE ?" "Phi%"])})]
         (is (= 3 (read-first-count-col r1)))
         (is (= 2 (read-first-count-col r2)))
         (is (= 2 (read-first-count-col s)))