Commits

Anonymous committed 754835b

documentation cleanup

Comments (0)

Files changed (1)

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

 (ns org.bituf.sqlrat.entity
   "Support Data Types (defrecord) as database entities and provide functions to
-   carry out database operations using the entities."
+  carry out database operations using the entities."
   (:use org.bituf.sqlrat.entity.internal)
   (:use org.bituf.sqlrat.util)
   (:use org.bituf.sqlrat.clause)
 
 (defmacro in-db
   "Create the context for executing database operations inside the macro body.
-   It provides with a database connection, which is automatically closed once
-   the body is executed completely. You must not return a lazy sequence that
-   tries to access the database *after* the body is executed.
-   Example: See the 'db-query' function
-   See also: in-txn"
+  It provides with a database connection, which is automatically closed once
+  the body is executed completely. You must not return a lazy sequence that
+  tries to access the database *after* the body is executed.
+  Example: See the 'db-query' function
+  See also: in-txn"
   [db & body]
   `(sql/with-connection ~db
     ~@body))
 
 (defmacro in-txn
   "Same as 'in-db' macro, but it creates a transaction in which the database
-   operations can take place. You should use this for executing write-operations
-   in transactions.
-   Example: See the 'save-row' function
-   See also: in-db"
+  operations can take place. You should use this for executing write-operations
+  in transactions.
+  Example: See the 'save-row' function
+  See also: in-db"
   [db & body]
   `(sql/with-connection ~db
     (sql/transaction
 
 (defn db-query
   "Fetch rows from database. Execute this with 'in-db' or 'in-txn'. When the
-   first argument is not a function (f) it simply collects the rows into a
-   vector an returns it - amount of memory consumed varies with the row count.
-   Arguments:
-     f     Is called with 'rows' as the only argument for processing them. It
-           must not return a lazy sequence that tries to access the database
-           *after* the 'db-query' function is executed.
-     query A vector containing the SQL in clojure.contrib.sql format. Examples
-           are: [\"SELECT * FROM emp\"] and [\"SELECT * FROM emp WHERE id=?\" 56]
-   Example:
-     (in-db mysql
-       (db-query (fn [rows] (count rows))
-         [\"SELECT * FROM emp WHERE id=?\" 56]))
-     => 135 ;; returns the row-count
-     (in-db mysql
-       (db-query [\"SELECT * FROM emp WHERE id=?\" 56]))
-     => [{<row1 data>} {<row2 data>} ...] ;; returns the rows as a vector
-   See also: with-db-query-results"
+  first argument is not a function (f) it simply collects the rows into a
+  vector an returns it - amount of memory consumed varies with the row count.
+  Arguments:
+    f     Is called with 'rows' as the only argument for processing them. It
+          must not return a lazy sequence that tries to access the database
+          *after* the 'db-query' function is executed.
+    query A vector containing the SQL in clojure.contrib.sql format. Examples
+          are: [\"SELECT * FROM emp\"] and [\"SELECT * FROM emp WHERE id=?\" 56]
+  Example:
+    (in-db mysql
+      (db-query (fn [rows] (count rows))
+        [\"SELECT * FROM emp WHERE id=?\" 56]))
+    => 135 ;; returns the row-count
+    (in-db mysql
+      (db-query [\"SELECT * FROM emp WHERE id=?\" 56]))
+    => [{<row1 data>} {<row2 data>} ...] ;; returns the rows as a vector
+  See also: with-db-query-results"
   ([^IFn f ^IPersistentVector query]
     (if *assert-args* (do
                         (assert (fn? f))
 
 (defmacro with-db-query-results
   "Wrapper macro for 'db-query'.
-   Arguments:
-     rows  Is bound to the rows fetched as a result of running the query
-     query The SQL query as described in 'db-query' function
-   Example:
-     (in-db mysql
-       (with-db-query-results rows [\"SELECT * FROM emp\"]
-         (println rows)))
-     => <rows-data>
-   See also: db-query"
+  Arguments:
+    rows  Is bound to the rows fetched as a result of running the query
+    query The SQL query as described in 'db-query' function
+  Example:
+    (in-db mysql
+      (with-db-query-results rows [\"SELECT * FROM emp\"]
+        (println rows)))
+    => <rows-data>
+  See also: db-query"
   [rows ^IPersistentVector sql-params & body]
   `(db-query (fn [~rows] ~@body) ~sql-params))
 
 
 (defn save-row
   "Save given row. Table should be specified as :tablename (keyword).
-   Row is simply a map of :columnName to value. Execute with in-txn or in-db.
-   Returns the saved row, which may have generated ID (if applicable).
-   Arguments:
-     table     The database table name (keyword)
-     row       The row (map of column-name to column-value) to be saved
-     id-column The primary ID column (keyword)
-   Examples:
-     (in-txn mysql
-       (save-row :emp {:code 9008 :name \"Joe Walker\"} :empid))
-     => {:empid 197 :code 9008 :name \"Joe Walker\"} ;; 197 is the generated ID
-     (in-txn mysql
-       (save-row :emp {:empid 197 :code 9667 :name \"Joe Hacker\"} :empid))
-     => {:empid 197 :code 1337 :name \"Joe Hacker\"} ;; updated code and name
-   See also: save"
+  Row is simply a map of :columnName to value. Execute with in-txn or in-db.
+  Returns the saved row, which may have generated ID (if applicable).
+  Arguments:
+    table     The database table name (keyword)
+    row       The row (map of column-name to column-value) to be saved
+    id-column The primary ID column (keyword)
+  Examples:
+    (in-txn mysql
+      (save-row :emp {:code 9008 :name \"Joe Walker\"} :empid))
+    => {:empid 197 :code 9008 :name \"Joe Walker\"} ;; 197 is the generated ID
+    (in-txn mysql
+      (save-row :emp {:empid 197 :code 9667 :name \"Joe Hacker\"} :empid))
+    => {:empid 197 :code 1337 :name \"Joe Hacker\"} ;; updated code and name
+  See also: save"
   [^Keyword table ^IPersistentMap row ^Keyword id-column]
   (let [id=? (str (name id-column) "=?")]
     (let [result (update-or-insert-values-returnid
 
 (defn relation
   "Factory function for creating a RelationMetadata instance. A relation is
-   defined between 'this' and 'that' entities. RelationMetadata is associated
-   with a certain 'this' entity, hence you need not specify 'this' entity.
-   Arguments:
-     this-col      (Keyword) The column in 'this' entity
-     that-ent      (EntityMetadata) The other entity
-     that-col      (Keyword) The column in 'that' entity
-     that-depends? (Boolean, optional, default false) Whether 'that' entity
-                   logically depends on 'this' entity
-   Example:
-     (relation :orderid item-metadata :itemid true) ;; order to item relation
-   See also: one-to-many, many-to-one, one-to-one, one-to-one-depends"
+  defined between 'this' and 'that' entities. RelationMetadata is associated
+  with a certain 'this' entity, hence you need not specify 'this' entity.
+  Arguments:
+    this-col      (Keyword) The column in 'this' entity
+    that-ent      (EntityMetadata) The other entity
+    that-col      (Keyword) The column in 'that' entity
+    that-depends? (Boolean, optional, default false) Whether 'that' entity
+                  logically depends on 'this' entity
+  Example:
+    (relation :orderid item-metadata :itemid true) ;; order to item relation
+  See also: one-to-many, many-to-one, one-to-one, one-to-one-depends"
   ([^Keyword this-col ^EntityMetadata that-ent ^Keyword that-col that-depends?]
     (RelationMetadata. this-col that-ent that-col that-depends?))
   ([^Keyword this-col ^EntityMetadata that-ent ^Keyword that-col]
 
 (defn one-to-many
   "Create one-to-many relation metadata.
-   Arguments: See 'relation' function
-   Example:
-     TODO
-   See also: relation"
+  Arguments: See 'relation' function
+  Example:
+    TODO
+  See also: relation"
   [^Keyword this-col ^EntityMetadata that-ent-meta ^Keyword that-col]
   (relation this-col that-ent-meta that-col true))
 
 
 (defn many-to-one
   "Create many-to-one relation metadata.
-   Arguments: See 'relation' function
-   Example:
-     TODO
-   See also: relation"
+  Arguments: See 'relation' function
+  Example:
+    TODO
+  See also: relation"
   [^Keyword this-col ^EntityMetadata that-ent-meta ^Keyword that-col]
   (relation this-col that-ent-meta that-col false))
 
 
 (defn rel-impl
   "Return implementation for the Relation protocol.
-   Arguments:
-     rels-vector  (Vector) of relation specs
-   Example: See extend-entity
-   See also: relation, extend-entity"
+  Arguments:
+    rels-vector  (Vector) of relation specs
+  Example: See extend-entity
+  See also: relation, extend-entity"
   [^IPersistentVector rels-vector]
   {:rel-meta (fn [this] (as-vector rels-vector))} )
 
 
 (defmacro from-row
   "Return a function that merges a value-map into a data type instance.
-   Arguments:
-     entity-creator  Body of code that creates/returns a data type instance
-   Example:
-     (from-row OrderItem.)
-   See also: entity-meta"
+  Arguments:
+    entity-creator  Body of code that creates/returns a data type instance
+  Example:
+    (from-row OrderItem.)
+  See also: entity-meta"
   [& entity-creator]
   `#(~@entity-creator {} %))
 
 
 (defn entity-meta
   "Factory function to create entity metadata. Arguments 'from-row-fn' and
-   'to-row-fn' let you abstract the row data away from the entity (useful when
-   entities cover a different perspective than the rows, for example during
-   Domain-driven design).
-   Arguments:
-     name        (Keyword) table name
-     id-col      (Keyword) ID column
-     from-row-fn (Function) that accepts a row (col-value map) as the only
-                 argument and converts it into an entity (data type instance).
-   Optional arguments:
-     :cols <v>      (Vector) of column specs. Each colum spec is a vector too.
-                    This is required *only* for the 'create-table' function.
-     :to-row-fn <v> (Function) that accepts entity (data type instance) as the
-                    only argument and converts into a row (key-value map).
-   Example:
-     (defrecord BlogEntry [])
-     (def blog-entry-meta
-       (entity-meta :entry :autoid (from-row BlogEntry.)
-         :cols [[:autoid     :int           \"NOT NULL PRIMARY KEY AUTO_INCREMENT\"]
-                [:title      \"varchar(30)\"  \"NOT NULL\"]
-                [:content    \"varchar(500)\" \"NOT NULL\"]
-                [:whenposted \"DATETIME\"     \"NOT NULL\"]
-                [:isdeleted  \"BOOLEAN\"      \"NOT NULL DEFAULT false\"]] ))
-   See also: Functions take entity metadata as argument."
+  'to-row-fn' let you abstract the row data away from the entity (useful when
+  entities cover a different perspective than the rows, for example during
+  Domain-driven design).
+  Arguments:
+    name        (Keyword) table name
+    id-col      (Keyword) ID column
+    from-row-fn (Function) that accepts a row (col-value map) as the only
+                argument and converts it into an entity (data type instance).
+  Optional arguments:
+    :cols <v>      (Vector) of column specs. Each colum spec is a vector too.
+                   This is required *only* for the 'create-table' function.
+    :to-row-fn <v> (Function) that accepts entity (data type instance) as the
+                   only argument and converts into a row (key-value map).
+  Example:
+    (defrecord BlogEntry [])
+    (def blog-entry-meta
+      (entity-meta :entry :autoid (from-row BlogEntry.)
+        :cols [[:autoid     :int           \"NOT NULL PRIMARY KEY AUTO_INCREMENT\"]
+               [:title      \"varchar(30)\"  \"NOT NULL\"]
+               [:content    \"varchar(500)\" \"NOT NULL\"]
+               [:whenposted \"DATETIME\"     \"NOT NULL\"]
+               [:isdeleted  \"BOOLEAN\"      \"NOT NULL DEFAULT false\"]] ))
+  See also: Functions take entity metadata as argument."
   [^Keyword name ^Keyword id ^IFn from-row-fn
    & {:keys [^IPersistentVector cols ^IFn to-row-fn]
       :or   {to-row-fn to-row}}]
 
 
 (defn entity-impl
-  "Factory function to create implementation for Entity protocol.
-   Arguments:
-     ent-metadata  (EntityMetadata) the Entity metadata
-   Example:
-     (entity-impl e-meta) ;; where e-meta is the entity metadata
-   See also: entity-meta"
+  "!Factory function! Create implementation for Entity protocol.
+  Arguments:
+    ent-metadata  (EntityMetadata) the Entity metadata
+  Example:
+    (entity-impl e-meta) ;; where e-meta is the entity metadata
+  See also: entity-meta"
   [^EntityMetadata ent-metadata]
   {:get-meta (fn [this] ent-metadata)} )
 
 
 (defn extend-entity
   "Associate an entity data type (hence all instances) with entity metadata and
-   relation metadata. This function may typically be called only once after the
-   entity data type is defined.
-   Arguments:
-     ent-type     The entity data type (not an instance)
-     ent-metadata Entity metadata
-     rel-metadata Relation metadata
-   Example:
-     (extend-entity BlogEntry blog-entry-meta
-       [(one-to-many :autoid  entry-comment-meta :entryid)] )
-   See also: entity-meta"
+  relation metadata. This function may typically be called only once after the
+  entity data type is defined.
+  Arguments:
+    ent-type     The entity data type (not an instance)
+    ent-metadata Entity metadata
+    rel-metadata Relation metadata
+  Example:
+    (extend-entity BlogEntry blog-entry-meta
+      [(one-to-many :autoid  entry-comment-meta :entryid)] )
+  See also: entity-meta"
   ([^Class ent-type ^EntityMetadata ent-metadata]
     (extend ent-type
       Entity   (entity-impl ent-metadata)))
 
 
 (defn read-count-col
-  "Read the value of count-col from specified row or entity. Return nil if the
-   the argument is nil."
+  "Read the value of count-col from specified row or entity."
   [^IPersistentMap row-or-entity]
-  (if *assert-args* (assert-arg #(or (nil? %) (map? %)) row-or-entity))
+  (if *assert-args* (assert-arg #(or (nil? %) (map? %))
+                      row-or-entity))
   (:sqlratcnt row-or-entity))
 
 
 (defn read-first-count-col
-  "Read the value of count-col from the first row/entity of a vector. Return nil
-   if the the argument is nil. Useful when the count-col is not grouped by some
-   column and hence there is just one row in the result set."
+  "Read the value of count-col from the first row/entity of a vector. Useful
+  when the count-col is not grouped by some column and hence there is just one
+  row in the result set."
   [^IPersistentVector row-vector]
-  (if *assert-args* (assert-arg #(or (nil? %) (vector? %)) row-vector))
+  (if *assert-args* (assert-arg #(or (nil? %) (vector? %))
+                      row-vector))
   (read-count-col (first row-vector)))
 
 
 (defn get-id-value
   "Return ID column value from entity"
   [^IPersistentMap entity]
+  (if *assert-args* (assert-arg entity? entity))
   ((get-id-column entity) entity))
 
 
 
 ;; function that accepts the (rel-meta entity) and returns a map
 ;; {:that-entity-name each-rel}
-(def dbrel-lookup-by-that-entity
+(def
+  ^{:doc
+  "Accept relation metadata as the only argument and return a map of
+  that-entity-name to each relation object. This is a memoized fn.
+  Example:
+    (let [rels (rel-meta entity)]
+      (dbrel-lookup-by-that-entity rels))
+    => {:that-entity-name1 rel-involving-that-entity1
+        :that-entity-name2 rel-involving-that-entity2
+        ...}"
+  }
+  dbrel-lookup-by-that-entity
   (memoize
     (fn [rels-vector]
       (let [rel-vector (as-vector rels-vector)
 
 
 (defn create-table
-  "Create table."
+  "Create table"
   [^EntityMetadata entity-meta]
+  (if *assert-args* (assert-as entity-meta EntityMetadata))
   (let [table-name (:name entity-meta)
         cols-spec  (:cols entity-meta)]
     (apply sql/create-table table-name cols-spec)))
 
 
 (defn drop-table
-  "Drop table."
+  "Drop table"
   [^EntityMetadata entity-meta]
+  (if *assert-args* (assert-as entity-meta EntityMetadata))
   (sql/drop-table (:name entity-meta)))
 
 
 (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."
+  a function that accepts result entities as an argument and must not return
+  something that lazily processes the entities.
+  TODO"
   ([^IFn f ^EntityMetadata entity-meta ^IPersistentVector sql-vec]
     (if *assert-args* (do
                         (assert (fn? f))
 
 
 (defmacro with-find-by-sql-results "Wrapper macro for find-by-sql"
-  [entities ^EntityMetadata entity-meta sql-vec & body]
+  [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."
+  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"
   ([^IFn f ^EntityMetadata entity-meta
     ^IPersistentMap {:keys [^IPersistentVector cols    ^IPersistentVector where
                             ^IPersistentVector groupby ^IPersistentVector other]
 
 (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."
+  :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]
 (defn save
   "Save given entity"
   [^Entity entity]
+  (if *assert-args* (assert-arg entity? entity))
   (let [ent-meta (get-meta entity)
         from-row-fn (:from-row-fn ent-meta)]
     (from-row-fn
 
 (defn delete
   "Delete entity. Variants:
-   [entity-meta id] >> delete by ID
-   [entity] >> delete given entity"
+  [entity-meta id] >> delete by ID
+  [entity] >> delete given entity
+  TODO"
   ([entity-meta id]
+    (if *assert-args* (assert-as entity-meta EntityMetadata))
     (sql/delete-rows (:name entity-meta)
       [(str (name (:id entity-meta)) "=?") id]))
   ([^Entity entity]
+    (if *assert-args* (assert-arg entity? entity))
     (delete (get-meta entity) (get-id-value entity))))
 
 
 
 (defn entity-rels-map
   "Build entity-relation map. You pass [e1 e2 e3] as entities and
-   [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"
+  [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"
   [^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
-   (the sequence) and must not return something that processes the arg lazily."
+  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
+  (the sequence) and must not return something that processes the arg lazily.
+  TODO"
   ([^IFn f ^IPersistentVector entities ^EntityMetadata that-meta
     ^IPersistentMap {:keys [^IPersistentVector cols    ^IPersistentVector where
                             ^IPersistentVector groupby ^IPersistentVector other]
 
 
 (defmacro with-find-rels-results
+  "TODO"
   [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)."
+  entity versus related-entities (see entity-rel-map function for details).
+  TODO"
   ([^IPersistentVector entities ^EntityMetadata that-meta
     ^IPersistentMap criteria]
     (entity-rels-map entities (find-rels entities that-meta criteria)))
 
 
 (defn save-deps [^Entity entity ^IPersistentVector dep-entities]
-  "Save dependents (THAT table) -- 1-to-many (has-many) relationships"
+  "Save dependents (THAT table) -- 1-to-many (has-many) relationships
+  TODO"
   (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,
-   :where, :groupby and :other attributes as in find-by-criteria function."
+  :where, :groupby and :other attributes as in find-by-criteria function.
+  TODO"
   ([^IFn f ^Entity entity ^Entity rel-entity
     ^IPersistentMap {:keys [cols where groupby other]
                      :or   {cols    [star-col]     ;; vector of col names
 
 
 (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
      ~criteria))
 
 
-(defn delete-cascade [entity]
-  [entity]
+(defn delete-cascade
   "Delete (cascaded) a given entity"
-  (if *assert-args* (do
-                      (assert (map? entity))))
+  [^Entity entity]
+  (if *assert-args* (assert-arg entity? entity))
   (let [rels (rel-meta entity)]
     (doseq [each rels]
       (if (:that-depends? each)
 (def max-col-print-width 40)
 (def delim " | ")
 
-(defn print-entities [entities]
+(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."
+  used as title. Passing an empty sequence of entities prints nothing at all.
+  TODO"
+  [^IPersistentVector entities]
   (mypp "\nENTITIES ***\n" entities)
   (if *assert-args*
     (do
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.