这几个函数能增加一点数据库结构的可读性,简单地省掉一些键盘时间:

;; ==============================================
;; 方便性的处理函数。对于每个 datomic 程序都有用!

(defn assoc-when [m k v]
  (if v (assoc m k v) m))

(defn attr
  "用缩略形式创建 schema 中的属性:
   每个属性必须有 ident 名称, type 类型和 doc 文档.
   可选用 :cardinality 指定数量以及 :unique 指定唯一性"
  [ident type doc
   & {:keys [cardinality unique]
      :or {cardinality :db.cardinality/one
           unique nil}}]
  (-> {:db/ident ident
       :db/valueType type
       :db/doc doc
       :db/cardinality cardinality
       :db.install/_attribute :db.part/db}
      (assoc-when :db/unique unique)))

(defn entities
  "给一组实体 ents 在 part 这个数据库分区中顺序生成临时 id"
  [part ents]
  (map #(assoc %1 :db/id (d/tempid part %2)) ents (iterate dec -1)))

(defn ensure-db
  "在 uri 上建立一个数据库, 它的结构为 schema, 如果有种子数据 seed-data,
   也记入数据库."
  [uri schema & [seed-data]]
  (d/create-database uri)
  (when-let [conn (d/connect uri)]
    (d/transact conn db-schema)
    (when seed-data
      (d/transact conn seed-data))))

下面这个数据库函数是传统的数据库上必不可少的:

(def seq-id
  "Transaction 函数. 给 eid 实体构造的 id-field 设置一个顺序的 id. 相当于传统数据库的
   sequence 或者自动增长功能.
   要求在数据的种子数据中建立一个实体有 :db/ident (函数中用 next-id 指定),
   这个实体有属性 next-value 来存储当前的最后 id 值."
  (d/function {:lang "clojure"
               :params '[db next-id next-value eid id-field]
               :code '(let [val (inc (get (d/entity db next-id) next-value 0))]
                        [{:db/id next-id next-value val}
                         {:db/id eid id-field val}])}))

使用例子

(def db-schema
  "数据库结构"
  (entities
   :db.part/db
   [(attr :user/name :db.type/string "用户名" :unique :db.unique/identity)

    (attr :product/id :db.type/string "产品号" :unique :db.unique/identity)
    (attr :product/cashValue :db.type/long "产品的人民币价值(分)")

    (attr :order/id :db.type/long "订单号" :unique :db.unique/identity)
    (attr :order/user :db.type/ref "下订单的用户")
    (attr :order/product :db.type/ref "订单所关联的产品")
    (attr :order/quantity :db.type/long "产品数量")

    (attr :orderId/value :db.type/long "顺序中下一个订单")]))

(def seed-data
  "种子数据"
  (entities
   :db.part/user
   [{:db/ident :orderId/next :orderId/value 10000}
    {:db/ident :nextId
     :db/doc (-> #'seq-id meta :doc)
     :db/fn seq-id}]))

robertluo
738 声望21 粉丝

引用和评论

0 条评论