`

Clojure学习——持久化框架clj-record

阅读更多
clj-record是仿Ruby on Rails ActiveRecord的一个持久化框架。项目源码在github上,使用说明写的很坑爹,就不能写个能跑起来的代码么。只是断断续续学了不久clojure,被逼去看源码,试了好几次,总算写出了能跑起来的代码。

添加依赖
[mysql/mysql-connector-java "5.1.21"]
[clj-record "1.1.4"]


样例代码:假设有test库,表名users,字段id,name,email。
(默认规则:model叫user,对应的表名叫users。之前一直搞错导致没初始化成功那些crud方法。)
(ns examples.user
  (:require clj-record.boot))

(def db {:subprotocol "mysql"
         :subname "//127.0.0.1:3306/test"
         :user "root"
         :password "123456"
         :auto-commit true
         :fetch-size  1000})

(clj-record.core/init-model)

;;列举几个常用的CRUD
;;具体其他方法可以查看一下clj-record.core的源码就知道了,都在宏定义中
(create {:name "pi" :email "tiger@hello.com"})

(update {:name "pi" :email "hello@tiger.com"})

(find-records {:name "pi"})
(all-records)

(destroy-record {:id 1})
(destroy-records {:name "pi"})


查看clj-record框架的clj-record.core的源码
(defmacro init-model
  "Macro to create a model out of a clojure namespace.
  The segment of the namespace name following the last dot is used as the model-name.
  Model-specific versions of most public functions in clj-record.core are defined 
  in the model namespace (minus the model-name as first argument).
  Optional forms for associations, validation, etc. are specified here.

  See test/clj_record/test_model/manufacturer.clj for an example."
  [& init-options]
  (let [model-name (last (string/split (name (ns-name *ns*)) #"\."))
        [top-level-options option-groups] (split-out-init-options init-options)
        tbl-name (or (top-level-options :table-name) (dashes-to-underscores (pluralize model-name)))
        optional-defs (defs-from-option-groups model-name option-groups)]
    `(do
      (init-model-metadata ~model-name)
      (set-db-spec ~model-name ~'db)
      (set-table-name ~model-name ~tbl-name)
      (def ~'model-name ~model-name)
      (def ~'table-name (table-name ~model-name))
      (defn ~'model-metadata [& args#]
        (apply model-metadata-for ~model-name args#))
      (defn ~'table-name [] (table-name ~model-name))
      (defn ~'record-count
        ([] (record-count ~model-name))
        ([attributes#] (record-count ~model-name attributes#)))
      (defn ~'get-record [id#]
        (get-record ~model-name id#))
      (defn ~'all-records []
        (all-records ~model-name))
      (defn ~'find-records [attributes#]
        (find-records ~model-name attributes#))
      (defn ~'find-record [attributes#]
        (find-record ~model-name attributes#))
      (defn ~'find-by-sql [select-query-and-values#]
        (find-by-sql ~model-name select-query-and-values#))
      (defn ~'create [attributes#]
        (create ~model-name attributes#))
      (defn ~'insert [attributes#]
        (insert ~model-name attributes#))
      (defn ~'update [attributes#]
        (update ~model-name attributes#))
      (defn ~'destroy-record [record#]
        (destroy-record ~model-name record#))
      (defn ~'destroy-records [attributes#]
        (destroy-records ~model-name attributes#))
      (defn ~'delete-records [attributes#]
        (delete-records ~model-name attributes#))
      (defn ~'validate [record#]
        (~'clj-record.validation/validate ~model-name record#))
      (defn ~'after-destroy [attributes#]
        (after-destroy ~model-name attributes#))
      (defn ~'after-insert [attributes#]
        (after-insert ~model-name attributes#))
      (defn ~'after-load [rows#]
        (after-load ~model-name rows#))
      (defn ~'after-save [attributes#]
        (after-save ~model-name attributes#))
      (defn ~'after-update [attributes#]
        (after-update ~model-name attributes#))
      (defn ~'after-validation [attributes#]
        (after-validation ~model-name attributes#))
      (defn ~'before-destroy [attributes#]
        (before-destroy ~model-name attributes#))
      (defn ~'before-insert [attributes#]
        (before-insert ~model-name attributes#))
      (defn ~'before-save [attributes#]
        (before-save ~model-name attributes#))
      (defn ~'before-update [attributes#]
        (before-update ~model-name attributes#))
      (defn ~'before-validation [attributes#]
        (before-validation ~model-name attributes#))
      ~@optional-defs)))


可以看出的几点:
1、默认的db是采用全局的db变量。
2、model-name默认是文件名。或者说ns的最后一部分
3、table-name可以init的时候作为参数传入。
4、do语句后面顺便帮我们初始化了些crud等方法。一开始没看懂,后来自己学着写了个小例子,总算明白。
user=> (defmacro init [] `(do (defn ~'say [attr#] (prn attr#))))
#'user/init
user=> (init)
#'user/say
user=> (say "hello")
"hello"
nil

这种感觉就像是有一个可以操作数据库的工具类,里面有很多静态方法,全部搬运到我们新建的类中。

(附件为这个例子的lein2工程。我用的IDE是Intellij IDEA。运行之前确定数据库和表存在。汗!!!)
参考资料
https://github.com/duelinmarkers/clj-record
0
1
分享到:
评论
1 楼 zk1878 2014-08-11  
推荐 korma

相关推荐

Global site tag (gtag.js) - Google Analytics