Refactoring in progress...
This commit is contained in:
parent
31848e75ca
commit
5ec60e524c
|
@ -5,7 +5,7 @@
|
|||
:license {:name "GNU Lesser General Public License, version 3.0 or (at your option) any later version"
|
||||
:url "https://www.gnu.org/licenses/lgpl-3.0.en.html"}
|
||||
|
||||
:dependencies [[adl-support "0.1.3"]
|
||||
:dependencies [[adl-support "0.1.4-SNAPSHOT"]
|
||||
[bouncer "1.0.1"]
|
||||
[clojure-saxon "0.9.4"]
|
||||
[environ "1.1.0"]
|
||||
|
@ -19,7 +19,10 @@
|
|||
:main adl.main
|
||||
|
||||
:plugins [[lein-codox "0.10.3"]
|
||||
[lein-release "1.0.5"]]
|
||||
[lein-kibit "0.1.6"]
|
||||
[lein-release "1.0.5"]
|
||||
;; [uncomplexor "0.1.0-SNAPSHOT"]
|
||||
]
|
||||
|
||||
;; :lein-release {:scm :git
|
||||
;; :deploy-via :clojars} ;; :deploy-via :clojars fails - with an scp error.
|
||||
|
|
|
@ -92,25 +92,24 @@
|
|||
(defn process
|
||||
"Process these parsed `options`."
|
||||
[options]
|
||||
(do
|
||||
(let [p (:path (:options options))
|
||||
op (if (.endsWith p "/") p (str p "/"))]
|
||||
(binding [*output-path* op
|
||||
*locale* (-> options :options :locale)
|
||||
*verbosity* (-> options :options :verbosity)]
|
||||
(make-parents *output-path*)
|
||||
(doall
|
||||
(map
|
||||
#(if
|
||||
(.exists (java.io.File. %))
|
||||
(let [application (x/parse (canonicalise %))]
|
||||
(h/to-hugsql-queries application)
|
||||
(j/to-json-routes application)
|
||||
(p/to-psql application)
|
||||
(s/to-selmer-routes application)
|
||||
(t/to-selmer-templates application))
|
||||
(*warn* (str "ERROR: File not found: " %)))
|
||||
(-> options :arguments)))))))
|
||||
(let [p (:path (:options options))
|
||||
op (if (.endsWith p "/") p (str p "/"))]
|
||||
(binding [*output-path* op
|
||||
*locale* (-> options :options :locale)
|
||||
*verbosity* (-> options :options :verbosity)]
|
||||
(make-parents *output-path*)
|
||||
(doall
|
||||
(map
|
||||
#(if
|
||||
(.exists (java.io.File. %))
|
||||
(let [application (x/parse (canonicalise %))]
|
||||
(h/to-hugsql-queries application)
|
||||
(j/to-json-routes application)
|
||||
(p/to-psql application)
|
||||
(s/to-selmer-routes application)
|
||||
(t/to-selmer-templates application))
|
||||
(*warn* (str "ERROR: File not found: " %)))
|
||||
(:arguments options))))))
|
||||
|
||||
|
||||
(defn -main
|
||||
|
@ -121,7 +120,7 @@
|
|||
(cond
|
||||
(empty? args)
|
||||
(usage options)
|
||||
(not (empty? (:errors options)))
|
||||
(seq (:errors options))
|
||||
(do
|
||||
(doall
|
||||
(map
|
||||
|
|
|
@ -46,13 +46,12 @@
|
|||
(let
|
||||
[entity-name (:name (:attrs entity))
|
||||
property-names (map #(:name (:attrs %)) properties)]
|
||||
(if
|
||||
(not (empty? property-names))
|
||||
(if-not (empty? property-names)
|
||||
(str
|
||||
"WHERE "
|
||||
(s/join
|
||||
"\n\tAND"
|
||||
(map #(str entity-name "." % " = :" %) property-names)))))))
|
||||
"WHERE "
|
||||
(s/join
|
||||
"\n\tAND"
|
||||
(map #(str entity-name "." % " = :" %) property-names)))))))
|
||||
|
||||
|
||||
(defn order-by-clause
|
||||
|
@ -213,8 +212,8 @@
|
|||
(defn select-query
|
||||
"Generate an appropriate `select` query for this `entity`"
|
||||
([entity properties]
|
||||
(if
|
||||
(not (empty? properties))
|
||||
(if-not
|
||||
(empty? properties)
|
||||
(let [entity-name (safe-name (:name (:attrs entity)) :sql)
|
||||
pretty-name (singularise entity-name)
|
||||
query-name (if (= properties (key-properties entity))
|
||||
|
@ -384,32 +383,24 @@
|
|||
[application]
|
||||
(let [filepath (str *output-path* "resources/sql/queries.auto.sql")]
|
||||
(make-parents filepath)
|
||||
(try
|
||||
(spit
|
||||
(do-or-warn
|
||||
(do
|
||||
(spit
|
||||
filepath
|
||||
(s/join
|
||||
"\n\n"
|
||||
(cons
|
||||
(emit-header
|
||||
"--"
|
||||
"File queries.sql"
|
||||
(str "autogenerated by adl.to-hugsql-queries at " (t/now))
|
||||
"See [Application Description Language](https://github.com/simon-brooke/adl).")
|
||||
(map
|
||||
#(:query %)
|
||||
(sort
|
||||
#(compare (:name %1) (:name %2))
|
||||
(vals
|
||||
(queries application)))))))
|
||||
(if (> *verbosity* 0)
|
||||
(*warn* (str "\tGenerated " filepath)))
|
||||
(catch
|
||||
Exception any
|
||||
(*warn*
|
||||
(str
|
||||
"ERROR: Exception "
|
||||
(.getName (.getClass any))
|
||||
(.getMessage any)
|
||||
" while printing "
|
||||
filepath))))))
|
||||
"\n\n"
|
||||
(cons
|
||||
(emit-header
|
||||
"--"
|
||||
"File queries.sql"
|
||||
(str "autogenerated by adl.to-hugsql-queries at " (t/now))
|
||||
"See [Application Description Language](https://github.com/simon-brooke/adl).")
|
||||
(map
|
||||
:query
|
||||
(sort
|
||||
#(compare (:name %1) (:name %2))
|
||||
(vals
|
||||
(queries application)))))))
|
||||
(if (pos? *verbosity*)
|
||||
(*warn* (str "\tGenerated " filepath)))))))
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@
|
|||
(f/unparse (f/formatters :basic-date-time) (t/now)))
|
||||
(list
|
||||
:require
|
||||
'[adl-support.core :as support]
|
||||
'[adl-support.core :refer :all]
|
||||
'[adl-support.rest-support :refer :all]
|
||||
'[clojure.core.memoize :as memo]
|
||||
'[clojure.java.io :as io]
|
||||
'[clojure.tools.logging :as log]
|
||||
|
@ -72,28 +73,38 @@
|
|||
(defn generate-handler-body
|
||||
"Generate and return the function body for the handler for this `query`."
|
||||
[query]
|
||||
(let [action (list
|
||||
(symbol (str "db/" (:name query)))
|
||||
'db/*db*
|
||||
(list 'support/massage-params
|
||||
'params
|
||||
'form-params
|
||||
(key-names (:entity query))))]
|
||||
(list
|
||||
['request]
|
||||
(list
|
||||
'let
|
||||
['params '(massage-params request)]
|
||||
(list
|
||||
[{:keys ['params 'form-params]}]
|
||||
(case
|
||||
(:type query)
|
||||
(:delete-1 :update-1)
|
||||
'valid-user-or-forbid
|
||||
(list
|
||||
'with-params-or-error
|
||||
(list
|
||||
'do-or-server-fail
|
||||
(list
|
||||
action
|
||||
`(log/debug (str ~(:name query) " called with params " ~'params "."))
|
||||
'(response/found "/"))
|
||||
(list
|
||||
'let
|
||||
(vector 'result action)
|
||||
`(log/debug (~(symbol (str "db/" (:name query) "-sqlvec")) ~'params))
|
||||
`(log/debug (str ~(str "'" (:name query) "' with params ") ~'params " returned " (count ~'result) " records."))
|
||||
(list 'response/ok 'result))))))
|
||||
(symbol (str "db/" (:name query)))
|
||||
'db/*db*
|
||||
'params)
|
||||
(case (:type query)
|
||||
:insert-1 201 ;; created
|
||||
:delete-1 204 ;; no content
|
||||
;; default
|
||||
200)) ;; OK
|
||||
'params
|
||||
(set
|
||||
(map
|
||||
#(keyword (:name (:attrs %)))
|
||||
(case (:type query)
|
||||
(:insert-1 :update-1)
|
||||
(-> query :entity insertable-properties)
|
||||
(:select-1 :delete-1)
|
||||
(-> query :entity key-properties)
|
||||
;; default
|
||||
nil))))
|
||||
'request))))
|
||||
|
||||
|
||||
(defn generate-handler-src
|
||||
|
@ -262,7 +273,7 @@
|
|||
(let [handlers-map (make-handlers-map application)
|
||||
filepath (str *output-path* "src/clj/" (:name (:attrs application)) "/routes/auto_json.clj")]
|
||||
(make-parents filepath)
|
||||
(try
|
||||
(do-or-warn
|
||||
(with-open [output (writer filepath)]
|
||||
(binding [*out* output]
|
||||
(pprint (file-header application))
|
||||
|
@ -275,16 +286,7 @@
|
|||
h)
|
||||
(sort (keys handlers-map))))
|
||||
(pprint (defroutes handlers-map))))
|
||||
(if (> *verbosity* 0)
|
||||
(*warn* (str "\tGenerated " filepath)))
|
||||
(catch
|
||||
Exception any
|
||||
(*warn*
|
||||
(str
|
||||
"ERROR: Exception "
|
||||
(.getName (.getClass any))
|
||||
(.getMessage any)
|
||||
" while printing "
|
||||
filepath))))))
|
||||
(if (pos? *verbosity*)
|
||||
(*warn* (str "\tGenerated " filepath))))))
|
||||
|
||||
|
||||
|
|
|
@ -111,7 +111,12 @@
|
|||
(defn emit-field-type
|
||||
[property entity application key?]
|
||||
(case (:type (:attrs property))
|
||||
"integer" (if key? "SERIAL" "INTEGER")
|
||||
"integer" (if
|
||||
(and
|
||||
key?
|
||||
(system-generated? property))
|
||||
"SERIAL"
|
||||
"INTEGER")
|
||||
"real" "DOUBLE PRECISION"
|
||||
("string" "image" "uploadable")
|
||||
(str "VARCHAR(" (:size (:attrs property)) ")")
|
||||
|
@ -150,8 +155,8 @@
|
|||
#(if (selector (:permission (:attrs %)))
|
||||
(safe-name (:group (:attrs %)) :sql))
|
||||
permissions)))]
|
||||
(if
|
||||
(not (empty? group-names))
|
||||
(if-not
|
||||
(empty? group-names)
|
||||
(s/join
|
||||
" "
|
||||
(list
|
||||
|
@ -318,12 +323,12 @@
|
|||
(str (safe-name entity) "." (field-name %)))
|
||||
(str (safe-name entity) "." (field-name %)))
|
||||
(filter
|
||||
#(not (= (:type (:attrs %)) "link"))
|
||||
#(not= (:type (:attrs %)) "link")
|
||||
(all-properties entity) )))))
|
||||
(str
|
||||
"FROM " (s/join ", " (set (compose-convenience-view-select-list entity application true))))
|
||||
(if
|
||||
(not (empty? entity-fields))
|
||||
(if-not
|
||||
(empty? entity-fields)
|
||||
(str
|
||||
"WHERE "
|
||||
(s/join
|
||||
|
@ -408,7 +413,7 @@
|
|||
(list
|
||||
doc-comment
|
||||
(map
|
||||
#(:content %)
|
||||
:content
|
||||
(children-with-tag entity :documentation))))
|
||||
(s/join
|
||||
" "
|
||||
|
@ -427,7 +432,7 @@
|
|||
(map
|
||||
#(emit-property % entity application false)
|
||||
(filter
|
||||
#(not (= (:type (:attrs %)) "link"))
|
||||
#(not= (:type (:attrs %)) "link")
|
||||
(children-with-tag entity :property)))))))
|
||||
"\n);")
|
||||
(map
|
||||
|
@ -532,7 +537,7 @@
|
|||
(str "(https://github.com/simon-brooke/adl) at "
|
||||
(f/unparse (f/formatters :basic-date-time) (t/now)))
|
||||
(map
|
||||
#(:content %)
|
||||
:content
|
||||
(children-with-tag application :documentation))))
|
||||
|
||||
|
||||
|
@ -568,18 +573,10 @@
|
|||
(:name (:attrs application))
|
||||
".postgres.sql")]
|
||||
(make-parents filepath)
|
||||
(try
|
||||
(do-or-warn
|
||||
(spit filepath (emit-application application))
|
||||
(if (> *verbosity* 0)
|
||||
(*warn* (str "\tGenerated " filepath)))
|
||||
(catch
|
||||
Exception any
|
||||
(*warn*
|
||||
(str
|
||||
"ERROR: Exception "
|
||||
(.getName (.getClass any))
|
||||
(.getMessage any)
|
||||
" while printing "
|
||||
filepath))))))
|
||||
(if
|
||||
(pos? *verbosity*)
|
||||
(*warn* (str "\tGenerated " filepath))))))
|
||||
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
(f/unparse (f/formatters :basic-date-time) (t/now)))
|
||||
(list
|
||||
:require
|
||||
'[adl-support.forms-support :refer :all]
|
||||
'[adl-support.core :as support]
|
||||
'[clojure.java.io :as io]
|
||||
'[clojure.set :refer [subset?]]
|
||||
|
@ -67,21 +68,15 @@
|
|||
|
||||
(defn make-form-handler-content
|
||||
[f e a n]
|
||||
(let [warning (list 'str (str "Error while fetching " (singularise (:name (:attrs e))) " record ") 'params)]
|
||||
(let [entity-name (singularise (:name (:attrs e)))]
|
||||
;; TODO: as yet makes no attempt to save the record
|
||||
(list 'let
|
||||
(vector
|
||||
'record (list
|
||||
'support/do-or-log-error
|
||||
;;(list 'if (list 'subset? (key-names e) (list 'set (list 'keys 'params)))
|
||||
(list
|
||||
(symbol
|
||||
(str "db/get-" (singularise (:name (:attrs e)))))
|
||||
(symbol "db/*db*")
|
||||
'params)
|
||||
;;)
|
||||
:message warning
|
||||
:error-return {:warnings [warning]}))
|
||||
'get-current-value
|
||||
(symbol (str "db/get-" entity-name))
|
||||
'params
|
||||
entity-name))
|
||||
(reduce
|
||||
merge
|
||||
{:error (list :warnings 'record)
|
||||
|
@ -199,10 +194,7 @@
|
|||
(vector 'request)
|
||||
(list 'let (vector
|
||||
'params
|
||||
(list 'support/massage-params
|
||||
(list 'keywordize-keys (list :params 'request))
|
||||
(list 'keywordize-keys (list :form-params 'request))
|
||||
(key-names e true)))
|
||||
(list 'support/massage-params 'request))
|
||||
(list
|
||||
'l/render
|
||||
(list 'support/resolve-template (str n ".html"))
|
||||
|
@ -303,7 +295,7 @@
|
|||
[application]
|
||||
(let [filepath (str *output-path* "src/clj/" (:name (:attrs application)) "/routes/auto.clj")]
|
||||
(make-parents filepath)
|
||||
(try
|
||||
(do-or-warn
|
||||
(with-open [output (writer filepath)]
|
||||
(binding [*out* output]
|
||||
(pprint (file-header application))
|
||||
|
@ -330,15 +322,7 @@
|
|||
(println)
|
||||
(pprint (make-defroutes application))
|
||||
(println)))
|
||||
(if (> *verbosity* 0)
|
||||
(*warn* (str "\tGenerated " filepath)))
|
||||
(catch
|
||||
Exception any
|
||||
(*warn*
|
||||
(str
|
||||
"ERROR: Exception "
|
||||
(.getName (.getClass any))
|
||||
(.getMessage any)
|
||||
" while printing "
|
||||
filepath))))))
|
||||
(if
|
||||
(pos? *verbosity*)
|
||||
(*warn* (str "\tGenerated " filepath))))))
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
(defn emit-content
|
||||
([content]
|
||||
(try
|
||||
(do-or-warn
|
||||
(cond
|
||||
(nil? content)
|
||||
nil
|
||||
|
@ -82,7 +82,7 @@
|
|||
"';\n"
|
||||
(-> any .getClass .getName)
|
||||
": "
|
||||
(-> any .getMessage)
|
||||
(.getMessage any)
|
||||
" -->"))))
|
||||
([filename application k]
|
||||
(emit-content filename nil nil application k))
|
||||
|
@ -356,9 +356,46 @@
|
|||
"{% endif %}")))})
|
||||
|
||||
|
||||
(defn compose-input-widget-para
|
||||
"Generate an input widget for this `field-or-property` of this `form` for
|
||||
this `entity` taken from within this `application`, in context of a para
|
||||
also containing its label."
|
||||
[property form entity application widget-name]
|
||||
(let
|
||||
[typedef (typedef property application)
|
||||
w-type (widget-type property application typedef)]
|
||||
(compose-widget-para
|
||||
property form entity application widget-name
|
||||
{:tag :input
|
||||
:attrs (merge
|
||||
{:id widget-name
|
||||
:name widget-name
|
||||
:type w-type
|
||||
:value (str "{{record." widget-name "}}")
|
||||
:maxlength (:size (:attrs property))
|
||||
:size (cond
|
||||
(nil? (:size (:attrs property)))
|
||||
"16"
|
||||
(try
|
||||
(> (read-string
|
||||
(:size (:attrs property))) 60)
|
||||
(catch Exception _ false))
|
||||
"60"
|
||||
true
|
||||
(:size (:attrs property)))}
|
||||
;; TODO: should match pattern from typedef
|
||||
(if
|
||||
(:minimum (:attrs typedef))
|
||||
{:min (:minimum (:attrs typedef))})
|
||||
(if
|
||||
(:maximum (:attrs typedef))
|
||||
{:max (:maximum (:attrs typedef))}))})))
|
||||
|
||||
|
||||
(defn widget
|
||||
"Generate a widget for this `field-or-property` of this `form` for this `entity`
|
||||
taken from within this `application`."
|
||||
taken from within this `application`, in context of a para also containing its
|
||||
label."
|
||||
[field-or-property form entity application]
|
||||
(let
|
||||
[widget-name (safe-name
|
||||
|
@ -370,13 +407,7 @@
|
|||
:property field-or-property
|
||||
:field (property-for-field field-or-property entity)
|
||||
;; default
|
||||
nil)
|
||||
permissions (find-permissions field-or-property property form entity application)
|
||||
typedef (typedef property application)
|
||||
w-type (widget-type property application typedef)
|
||||
visible-to (visible-to permissions)
|
||||
;; if the form isn't actually a form, no widget is writeable.
|
||||
writeable-by (if (= (:tag form) :form) (writeable-by permissions))]
|
||||
nil)]
|
||||
(if
|
||||
property
|
||||
(case w-type
|
||||
|
@ -396,31 +427,7 @@
|
|||
:attrs {:rows "8" :cols "60" :id widget-name :name widget-name}
|
||||
:content [(str "{{record." widget-name "}}")]})
|
||||
;; all others
|
||||
(compose-widget-para
|
||||
property form entity application widget-name
|
||||
{:tag :input
|
||||
:attrs (merge
|
||||
{:id widget-name
|
||||
:name widget-name
|
||||
:type w-type
|
||||
:value (str "{{record." widget-name "}}")
|
||||
:maxlength (:size (:attrs property))
|
||||
:size (cond
|
||||
(nil? (:size (:attrs property)))
|
||||
"16"
|
||||
(try
|
||||
(> (read-string
|
||||
(:size (:attrs property))) 60)
|
||||
(catch Exception _ false))
|
||||
"60"
|
||||
true
|
||||
(:size (:attrs property)))}
|
||||
(if
|
||||
(:minimum (:attrs typedef))
|
||||
{:min (:minimum (:attrs typedef))})
|
||||
(if
|
||||
(:maximum (:attrs typedef))
|
||||
{:max (:maximum (:attrs typedef))}))})))))
|
||||
(compose-input-widget-para property form entity application widget-name)))))
|
||||
|
||||
|
||||
(defn embed-script-fragment
|
||||
|
@ -898,7 +905,7 @@
|
|||
(let [filepath (str *output-path* "resources/templates/auto/" filename)]
|
||||
(if
|
||||
template
|
||||
(try
|
||||
(do-or-warn
|
||||
(do
|
||||
(make-parents filepath)
|
||||
(spit
|
||||
|
@ -917,7 +924,9 @@
|
|||
"{% endblock %}"))
|
||||
(keys template)))
|
||||
(file-footer filename application)))))
|
||||
(if (> *verbosity* 0) (*warn* "\tGenerated " filepath)))
|
||||
(if
|
||||
(pos? *verbosity*)
|
||||
(*warn* "\tGenerated " filepath)))
|
||||
(catch Exception any
|
||||
(let [report (str
|
||||
"ERROR: Exception "
|
||||
|
@ -925,7 +934,7 @@
|
|||
(.getMessage any)
|
||||
" while printing "
|
||||
filepath)]
|
||||
(try
|
||||
(do-or-warn
|
||||
(spit
|
||||
filepath
|
||||
(with-out-str
|
||||
|
@ -962,7 +971,7 @@
|
|||
#(if
|
||||
(templates-map %)
|
||||
(let [filename (str (name %) ".html")]
|
||||
(try
|
||||
(do-or-warn
|
||||
(write-template-file filename (templates-map %) application)
|
||||
(catch Exception any
|
||||
(*warn*
|
||||
|
|
|
@ -19,54 +19,67 @@
|
|||
(= a b)))
|
||||
|
||||
(deftest entity-tests
|
||||
(let [xml {:tag :entity,
|
||||
:attrs {:name "address"},
|
||||
(let [application {:tag :application,
|
||||
:attrs {:version "0.1.1", :name "test-app"},
|
||||
:content
|
||||
[{:tag :key,
|
||||
:attrs nil,
|
||||
[{:tag :entity,
|
||||
:attrs {:name "address"},
|
||||
:content
|
||||
[{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "system",
|
||||
:type "integer",
|
||||
:name "id"},
|
||||
[{:tag :key,
|
||||
:attrs nil,
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}]}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:distinct "user", :size "128", :type "string", :name "street"},
|
||||
:content nil}
|
||||
{:tag :property,
|
||||
:attrs {:size "64", :type "string", :name "town"},
|
||||
:content nil}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:distinct "user", :size "12", :type "string", :name "postcode"},
|
||||
:content nil}]}]
|
||||
[{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "system",
|
||||
:type "integer",
|
||||
:name "id"},
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "all",
|
||||
:generator "assigned"
|
||||
:type "string",
|
||||
:size "12"
|
||||
:name "postcode"},
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}
|
||||
]}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:distinct "user", :size "128", :type "string", :name "street"},
|
||||
:content nil}
|
||||
{:tag :property,
|
||||
:attrs {:size "64", :type "string", :name "town"},
|
||||
:content nil}
|
||||
]}]}
|
||||
entity (child-with-tag application :entity)]
|
||||
(testing "user distinct properties should provide the default ordering"
|
||||
(let [expected
|
||||
"ORDER BY address.street,
|
||||
address.postcode,
|
||||
address.id"
|
||||
actual (order-by-clause xml)]
|
||||
actual (order-by-clause entity)]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "keys name extraction"
|
||||
(let [expected '("id")
|
||||
actual (key-names xml)]
|
||||
(let [expected #{"id"}
|
||||
actual (key-names entity)]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "primary key test"
|
||||
(let [expected true
|
||||
actual (has-primary-key? xml)]
|
||||
actual (has-primary-key? entity)]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "non-key properties test"
|
||||
(let [expected true
|
||||
actual (has-non-key-properties? xml)]
|
||||
actual (has-non-key-properties? entity)]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "insert query generation"
|
||||
(let [expected "-- :name create-addres! :! :n
|
||||
-- :doc creates a new addres record
|
||||
(let [expected "-- :name create-address! :! :n
|
||||
-- :doc creates a new address record
|
||||
INSERT INTO address (street,
|
||||
town,
|
||||
postcode)
|
||||
|
@ -74,25 +87,25 @@
|
|||
':town',
|
||||
':postcode')
|
||||
returning id\n\n"
|
||||
actual (:query (first (vals (insert-query xml))))]
|
||||
actual (:query (first (vals (insert-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "insert query signature"
|
||||
(let [expected ":! :n"
|
||||
actual (:signature (first (vals (insert-query xml))))]
|
||||
actual (:signature (first (vals (insert-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "update query generation"
|
||||
(let [expected "-- :name update-addres! :! :n
|
||||
-- :doc updates an existing addres record
|
||||
(let [expected "-- :name update-address! :! :n
|
||||
-- :doc updates an existing address record
|
||||
UPDATE address
|
||||
SET street = :street,
|
||||
town = :town,
|
||||
postcode = :postcode
|
||||
WHERE address.id = :id\n\n"
|
||||
actual (:query (first (vals (update-query xml))))]
|
||||
actual (:query (first (vals (update-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "update query signature"
|
||||
(let [expected ":! :n"
|
||||
actual (:signature (first (vals (update-query xml))))]
|
||||
actual (:signature (first (vals (update-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "search query generation"
|
||||
(let [expected "-- :name search-strings-addres :? :1
|
||||
|
@ -106,22 +119,22 @@
|
|||
address.id
|
||||
--~ (if (:offset params) \"OFFSET :offset \")
|
||||
--~ (if (:limit params) \"LIMIT :limit\" \"LIMIT 100\")\n\n"
|
||||
actual (:query (first (vals (search-query xml))))]
|
||||
actual (:query (first (vals (search-query entity application))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "search query signature"
|
||||
(let [expected ":? :1"
|
||||
actual (:signature (first (vals (search-query xml))))]
|
||||
actual (:signature (first (vals (search-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "select query generation"
|
||||
(let [expected "-- :name get-addres :? :1
|
||||
-- :doc selects an existing addres record
|
||||
SELECT * FROM address
|
||||
WHERE address.id = :id\n\n"
|
||||
actual (:query (first (vals (select-query xml))))]
|
||||
actual (:query (first (vals (select-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "select query signature"
|
||||
(let [expected ":? :1"
|
||||
actual (:signature (first (vals (select-query xml))))]
|
||||
actual (:signature (first (vals (select-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "list query generation"
|
||||
(let [expected "-- :name list-address :? :*
|
||||
|
@ -132,75 +145,79 @@
|
|||
address.id
|
||||
--~ (if (:offset params) \"OFFSET :offset \")
|
||||
--~ (if (:limit params) \"LIMIT :limit\" \"LIMIT 100\")\n\n"
|
||||
actual (:query (first (vals (list-query xml))))]
|
||||
actual (:query (first (vals (list-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "list query signature"
|
||||
(let [expected ":? :*"
|
||||
actual (:signature (first (vals (list-query xml))))]
|
||||
actual (:signature (first (vals (list-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "delete query generation"
|
||||
(let [expected "-- :name delete-addres! :! :n
|
||||
-- :doc updates an existing addres record
|
||||
DELETE FROM address
|
||||
WHERE address.id = :id\n\n"
|
||||
actual (:query (first (vals (delete-query xml))))]
|
||||
actual (:query (first (vals (delete-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "delete query signature"
|
||||
(let [expected ":! :n"
|
||||
actual (:signature (first (vals (delete-query xml))))]
|
||||
actual (:signature (first (vals (delete-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
|
||||
))
|
||||
|
||||
(deftest complex-key-tests
|
||||
(let [xml {:tag :entity,
|
||||
:attrs {:name "address"},
|
||||
(let [application {:tag :application,
|
||||
:attrs {:version "0.1.1", :name "test-app"},
|
||||
:content
|
||||
[{:tag :key,
|
||||
:attrs nil,
|
||||
[{:tag :entity,
|
||||
:attrs {:name "address"},
|
||||
:content
|
||||
[{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "system",
|
||||
:type "integer",
|
||||
:name "id"},
|
||||
[{:tag :key,
|
||||
:attrs nil,
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}
|
||||
[{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "system",
|
||||
:type "integer",
|
||||
:name "id"},
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "all",
|
||||
:generator "assigned"
|
||||
:type "string",
|
||||
:size "12"
|
||||
:name "postcode"},
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}
|
||||
]}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:immutable "true",
|
||||
:required "true",
|
||||
:distinct "all",
|
||||
:generator "assigned"
|
||||
:type "string",
|
||||
:size "12"
|
||||
:name "postcode"},
|
||||
:content
|
||||
[{:tag :generator, :attrs {:action "native"}, :content nil}]}
|
||||
]}
|
||||
{:tag :property,
|
||||
:attrs
|
||||
{:distinct "user", :size "128", :type "string", :name "street"},
|
||||
:content nil}
|
||||
{:tag :property,
|
||||
:attrs {:size "64", :type "string", :name "town"},
|
||||
:content nil}
|
||||
]}]
|
||||
{:distinct "user", :size "128", :type "string", :name "street"},
|
||||
:content nil}
|
||||
{:tag :property,
|
||||
:attrs {:size "64", :type "string", :name "town"},
|
||||
:content nil}
|
||||
]}]}
|
||||
entity (child-with-tag application :entity)]
|
||||
(testing "user distinct properties should provide the default ordering"
|
||||
(let [expected "ORDER BY address.street,
|
||||
address.postcode,
|
||||
address.id"
|
||||
actual (order-by-clause xml)]
|
||||
actual (order-by-clause entity)]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "keys name extraction"
|
||||
(let [expected '("id" "postcode")
|
||||
actual (key-names xml)]
|
||||
(let [expected #{"id" "postcode"}
|
||||
actual (key-names entity)]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "insert query generation - compound key, non system generated field in key"
|
||||
(let [expected "-- :name create-addres! :! :n
|
||||
-- :doc creates a new addres record
|
||||
(let [expected "-- :name create-address! :! :n
|
||||
-- :doc creates a new address record
|
||||
INSERT INTO address (street,
|
||||
town,
|
||||
postcode)
|
||||
|
@ -209,17 +226,17 @@
|
|||
':postcode')
|
||||
returning id,
|
||||
postcode\n\n"
|
||||
actual (:query (first (vals (insert-query xml))))]
|
||||
actual (:query (first (vals (insert-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "update query generation - compound key"
|
||||
(let [expected "-- :name update-addres! :! :n
|
||||
-- :doc updates an existing addres record
|
||||
(let [expected "-- :name update-address! :! :n
|
||||
-- :doc updates an existing address record
|
||||
UPDATE address
|
||||
SET street = :street,
|
||||
town = :town
|
||||
WHERE address.id = :id
|
||||
AND address.postcode = ':postcode'\n\n"
|
||||
actual (:query (first (vals (update-query xml))))]
|
||||
actual (:query (first (vals (update-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "search query generation - user-distinct field in key"
|
||||
(let [expected "-- :name search-strings-addres :? :1
|
||||
|
@ -233,7 +250,7 @@
|
|||
address.id
|
||||
--~ (if (:offset params) \"OFFSET :offset \")
|
||||
--~ (if (:limit params) \"LIMIT :limit\" \"LIMIT 100\")\n\n"
|
||||
actual (:query (first (vals (search-query xml))))]
|
||||
actual (:query (first (vals (search-query entity application))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))
|
||||
(testing "delete query generation - compound key"
|
||||
(let [expected "-- :name delete-addres! :! :n
|
||||
|
@ -241,6 +258,6 @@
|
|||
DELETE FROM address
|
||||
WHERE address.id = :id
|
||||
AND address.postcode = ':postcode'\n\n"
|
||||
actual (:query (first (vals (delete-query xml))))]
|
||||
actual (:query (first (vals (delete-query entity))))]
|
||||
(is (string-equal-ignore-whitespace? actual expected))))))
|
||||
|
||||
|
|
Loading…
Reference in a new issue