<div>Hi,</div><div><br></div><div>(I am cross-posting this on Clojure and Hibernate-users mailing list.)</div><div><br></div><div>DISCLAIMER: I am a Clojure newbie - please let me know if you find any of my assumptions / statements to be incorrect.</div>
<div><br></div><div><br></div><div>Hibernate has an experimental support for working with maps rather than POJOs using the following configuration property:</div><div><br></div><div>hibernate.default_entity_mode=dynamic-map</div>
<div><br></div><div>I have done few simple successful tests using the above-mentioned technique, using Clojure/Hibernate/XML-hbm-files. The stack I tested these with is below:</div><div><br></div><div>Windows XP 32-bit SP3</div>
<div>Sun JDK 1.6</div><div>Clojure 1.0</div><div>Hibernate 3.2</div><div>PostgreSQL 8.3</div><div>JDBC 3 driver</div><div><br></div><div><br></div><div>I am wondering if I can take this idea to a larger implementation scale using Clojure. What I intend to achieve is described below in detail. The intention of this post is to communicate the idea and gather feedback - please provide your input, feedback, suggestions and warnings.</div>
<div><br></div><div><br></div><div>- I am trying to visualize a dual layered easy-ORM for Clojure using a subset of Hibernate. The first layer &quot;Hibernate integration primitives&quot; will provide low level access to Hibernate functionaly using Clojure and another layer &quot;Easy ORM semantics&quot; will build on the top of the first layer and will provide Django / ActiveRecord like ease of use.</div>
<div><br></div><div>- The domain model will be expressed using Clojure syntax (DSL). As a pre-compile step, a utility function will process the domain model to automatically generate Hibernate XML-mapping files. Those XML-mapping files can be used to carry out hbm2ddl (optional) activities. The domain model will also be rich enough to capture metadata for subsequent Hibernate operations.</div>
<div><br></div><div>                    .-----&gt; Auto-generate Hibernate XML as a precompile step</div><div>                   /</div><div>                  /</div><div>    Clojure ORM Domain Model</div><div>                  \</div>
<div>                   \</div><div>                    *-----&gt; Keep model&#39;s metadata in Clojure</div><div>                          (so that they can be applied in subsequent operations)</div><div><br></div><div>- The captured domain model will retain information about entity-identification, property names, associations etc. A fictitious sample (only for example, not necessarily correct syntax) is given below:</div>
<div><br></div><div>    ; define model (HBM = Hibernate Mapping)</div><div>    ;</div><div>    ; extra (optional) attributes appear in the map</div><div>    ;</div><div>    (defmodel :blogentry                      ; assumed :entity-name=:blogentry, :table=(upper-case :blogentry)</div>
<div><br></div><div>      (hbm-id :id :long {:column &quot;AUTO_ID&quot; :generator &quot;sequence&quot; :sequence-name &quot;blogentry_auto_id_seq&quot;})   ; assumed :name=:id, :type=:long, :column=&quot;AUTO_ID&quot;</div>
<div><br></div><div>      (hbm-property :title       :string    {:width 100 }) ; assumed :name=:title,       :type=:string,    :column=(upper-case :title)</div><div><br></div><div>      (hbm-property :content     :string    {:width 3000}) ; assumed :name=:content,     :type=:string,    :column=(upper-case :content)</div>
<div><br></div><div>      (hbm-property :when-posted :timestamp              ) ; assumed :name=:when-posted, :type=:timestamp, :column=(upper-case (dash-to-underscore :when-posted))</div><div><br></div><div>      (hbm-property :is-deleted  :boolean                ) ; assumed :name=:is-deleted,  :type=:boolean,   :column=(upper-case (dash-to-underscore :is-deleted))</div>
<div><br></div><div>      (hbm-property :sample      :integer   {:column &quot;SAMPLE_CHAPTER&quot; }) ; assumed :name=:sample, :type=:integer, :column=&quot;SAMPLE_CHAPTER&quot;)</div><div><br></div><div>      ; associations</div>
<div>      (hbm-many-to-one     :blog {:column &quot;BLOG_ID&quot; :entity :blog-entity})</div><div><br></div><div>      (hbm-set-one-to-many :usercomments {:key-column &quot;AUTO_ID&quot;, :entity :usercomments-entity} ))</div>
<div><br></div><div>    (defn create-blog-instance []</div><div><br></div><div>      (model-instance :blogentry</div><div><br></div><div>        { :title &quot;Nandi Hills&quot;, :content &quot;Fill here&quot;, :when-posted (time-now), :is-deleted false } ))</div>
<div><br></div><div>    ; create instance and persist (HBO = Hibernate Operation)</div><div>    ;</div><div>    (let [blogentry (create-blog-instance)]</div><div><br></div><div>      (hbo-persist blogentry))</div><div><br>
</div><div>- There will be a Clojure DSL for persistence operations (that ultimately translates into HQL or JPA QL). Some examples are below:</div><div><br></div><div>    (hbo-persist    blogentry-instance)</div><div><br>
</div><div>    (hbo-findby-id  blogentry 45)</div><div><br></div><div>    (:blog (hbo-findby-id blogentry 45))                               ; returns the blog entity from many-to-one association</div><div><br></div><div>
    (hbo-findby-any blogentry (:where [:eq :title &quot;Amarnath Trip&quot;]))</div><div><br></div><div>    (hbo-findby-any [blogentry :e usercomments :c] (:where [:eq [:e :id] [:c :entry-id]]) ; Join</div><div><br></div>
<div>    (hbo-findby-any usercomments (:where [:not-in (:select [:id] :from [:spammers])]))    ; Sub-select</div><div><br></div><div>    (hbo-updateall  blogentry :set [:title &quot;New title&quot; :is-deleted false])</div>
<div><br></div><div>    (hbo-updateby-any  blogentry :set [:title &quot;New title&quot; :is-deleted false] (:where [:gt :when-posted (parse-date &quot;2009-06-30&quot;)]) )</div><div><br></div><div>    (hbo-deleteby-id blogentry 57)</div>
<div><br></div><div><br></div><div>- These are the simple design notes:</div><div><br></div><div>    ;- DSL Syntax for models should capture both Hibernate mapping and model metadata</div><div>    ;</div><div>    ;- Remain close to Hibernate idioms, but do not inherit the XML-wrinkles</div>
<div>    ;</div><div>    ;- Important HBM attributes are mandatory parameters in the domain model</div><div>    ;</div><div>    ;- Rest of the (optional) attributes can appear as a map e.g. {:column &quot;CUSTOMER&quot;}</div>
<div>    ;</div><div>    ;- Simplify in favour of succinctness (Sensible and auto-deduced metadata defaults)</div><div>    ;</div><div>    ;- Overridable simplicity (Can override attributes by providing maps, add children)</div>
<div>    ;</div><div>    ;- Not everything is covered - use hbm-any for direct Hibernate API access (cook your own)</div><div>    ;</div><div>    ;- Use Clojure metadata support and (Cannot avoid) macros for model definition</div>
<div>    ;</div><div>    ;- Use multimethods for XML auto-generation</div><div>    ;</div><div>    ;- Use macros and multimethods for persistence operations (render as HQL / JPA QL)</div><div><br></div><div><br></div><div>
Regards,</div><div>Shantanu</div><div><br></div>