diff --git a/src/adl_support/filters.clj b/src/adl_support/filters.clj index 7c31b55..262aefb 100644 --- a/src/adl_support/filters.clj +++ b/src/adl_support/filters.clj @@ -4,7 +4,8 @@ adl-support.filters (:require [clojure.string :as s] [selmer.filters :as f] - [selmer.parser :as p])) + [selmer.parser :as p] + [selmer.tags :as t])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -64,3 +65,24 @@ (f/add-filter! :email email) ;; (p/render "{{p|telephone}}" {:p "07768 130255"}) + +(defn contains + [collection value] + (first + (filter + #(= % value) + collection))) + +;; (contains '(:a :b :c) :a) + +(f/add-filter! :contains contains) + +;; (p/render "{{l|contains:\"foo\"}}" {:l ["froboz" "bar"]}) + +;; (p/render "{% if l|contains:\"foo\" %}I see ya!{% else %}I don't{% endif %}" {:l ["foo" "bar"]}) +;; (p/render "{% if l|contains:\"foo\" %}I see ya!{% else %}I don't{% endif %}" {:l ["froboz" "bar"]}) + +;; (p/render +;; "" +;; {:option {:id 2 :name "Fred"} :record {:roles [2 6]}}) + diff --git a/src/adl_support/tags.clj b/src/adl_support/tags.clj index c808500..d592937 100644 --- a/src/adl_support/tags.clj +++ b/src/adl_support/tags.clj @@ -2,7 +2,9 @@ in generated templates." :author "Simon Brooke"} adl-support.tags - (:require [selmer.parser :as p])) + (:require [clojure.string :refer [split]] + [selmer.parser :as p] + [selmer.tags :as t])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; @@ -32,6 +34,22 @@ success failure)) + +(defn parse-arg + [arg context] + (cond + (number? arg) + arg + (number? (read-string arg)) + (read-string arg) + (= \" (first arg)) + (.substring arg 1 (dec (.length arg))) + (and (= \: (first arg)) (> (count arg) 1)) + (keyword (subs arg 1)) + :else + (get-in context (map keyword (split arg #"\."))))) + + (defn add-tags [] "Add custom tags required by ADL-generated code to the parser's tags." (p/add-tag! :ifmemberof @@ -43,6 +61,24 @@ :else (fn [args context content] "") - :endifmemberof)) + :endifmemberof) + (p/add-tag! :ifcontains + (fn [[c v] context content] + (let [value (parse-arg v context) + collection (parse-arg c context)] + (if + (some + #(= % value) + collection) + (get-in content [:ifcontains :content]) + (get-in content [:else :content])))) + :else + (fn [args context content] + "") + :endifcontains)) + (add-tags) + + + diff --git a/src/adl_support/utils.clj b/src/adl_support/utils.clj index 8f8ac6b..5d26e19 100644 --- a/src/adl_support/utils.clj +++ b/src/adl_support/utils.clj @@ -322,22 +322,6 @@ (= (max n1 n2) 1))) -(defn link-related-query-name - "link is tricky. If there's exactly than one link between the two - entities, we need to generate the same name from both - ends of the link" - [property nearside farside] - (if (unique-link? nearside farside) - (let [ordered (sort-by #(-> % :attrs :name) (list nearside farside))] - (str "list-" - (safe-name (first ordered) :sql) - "-by-" - (safe-name (nth ordered 1) :sql))) - (str "list-" - (safe-name property :sql) "-by-" - (singularise (safe-name nearside :sql))))) - - (defn link-table-name "Canonical name of a link table between entity `e1` and entity `e2`. However, there may be different links between the same two tables with different semantics; if @@ -364,25 +348,22 @@ `farside` are both entities." [property nearside farside] (if - (and + (and (property? property) (entity? nearside) (entity? farside)) - (case (-> property :attrs :type) - "link" (link-related-query-name property nearside farside) - "list" (str "list-" - (safe-name farside :sql) "-by-" - (singularise (safe-name nearside :sql))) - "entity" (str "list-" - (safe-name nearside :sql) "-by-" - (singularise (safe-name farside :sql))) - ;; default - (str "ERROR-bad-property-type-" - (-> ~property :attrs :type) "-of-" - (-> ~property :attrs :name))) - (do - (*warn* "Argument passed to `list-related-query-name` was a non-entity") - nil))) + (case (-> property :attrs :type) + ("link" "list") (str "list-" + (safe-name farside :sql) "-by-" + (singularise (safe-name nearside :sql))) + "entity" (str "get-" (singularise (safe-name farside :sql))) + ;; default + (str "ERROR-bad-property-type-" + (-> ~property :attrs :type) "-of-" + (-> ~property :attrs :name))) + (do + (*warn* "Argument passed to `list-related-query-name` was a non-entity") + nil))) (defn property-for-field diff --git a/test/adl_support/tags_test.clj b/test/adl_support/tags_test.clj index 578deed..356d2a3 100644 --- a/test/adl_support/tags_test.clj +++ b/test/adl_support/tags_test.clj @@ -6,7 +6,7 @@ (add-tags) (deftest if-member-of-tests - (testing "testing the if-member-of tag" + (testing "the `ifmemberof` tag" (let [expected "boo" actual (if-member-of-permitted nil nil "caramba" "boo")] (is (= expected actual) "Nil args, nil ")) @@ -48,3 +48,75 @@ +(deftest if-contains-tests + (testing "the `ifcontains` tag" + (let [expected "Hello!" + actual (parser/render "{% ifcontains record.roles option.id %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id 2 :name "Fred"} :record {:roles [2 6]}})] + (is (= expected actual) + "Both args are paths which exist in the context; + the value of the first contains the value of the second; + values are numbers")) + (let [expected "Goodbye!" + actual (parser/render "{% ifcontains record.roles option.id %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id 3 :name "Ginny"} :record {:roles [2 6]}})] + (is (= expected actual) + "Both args are paths which exist in the context; + the value of the first does not contain the value of the second; + values are numbers")) + (let [expected "Hello!" + actual (parser/render "{% ifcontains record.roles option.id %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id :two :name "Fred"} :record {:roles [:two :six]}})] + (is (= expected actual) + "Both args are paths which exist in the context; + the value of the first contains the value of the second; + values are keywords")) + (let [expected "Goodbye!" + actual (parser/render "{% ifcontains record.roles option.id %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id :three :name "Ginny"} :record {:roles [:two :six]}})] + (is (= expected actual) + "Both args are paths which exist in the context; + the value of the first does not contain the value of the second; + values are keywords")) + (let [expected "Hello!" + actual (parser/render "{% ifcontains record.roles option.id %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id "two" :name "Fred"} :record {:roles ["two" "six"]}})] + (is (= expected actual) + "Both args are paths which exist in the context; + the value of the first contains the value of the second; + values are strings")) + (let [expected "Goodbye!" + actual (parser/render "{% ifcontains record.roles option.id %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id "three" :name "Ginny"} :record {:roles ["two" "six"]}})] + (is (= expected actual) + "Both args are paths which exist in the context; + the value of the first does not contain the value of the second; + values are strings")) + (let [expected "Hello!" + actual (parser/render "{% ifcontains record.roles 2 %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id 4 :name "Henry"} :record {:roles [2 6]}})] + (is (= expected actual) + "First arg is a path which exists in the context, second is a literal number; + the value of the first contains the value of the second; + values are numbers")) + (let [expected "Goodbye!" + actual (parser/render "{% ifcontains record.roles 3 %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id 3 :name "Ginny"} :record {:roles [2 6]}})] + (is (= expected actual) + "First arg is a path which exists in the context, second is a literal number; + the value of the first does not contain the value of the second; + values are numbers")) + (let [expected "Hello!" + actual (parser/render "{% ifcontains record.roles :two %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id 4 :name "Henry"} :record {:roles [:two :six]}})] + (is (= expected actual) + "First arg is a path which exists in the context, second is a literal keyword; + the value of the first contains the value of the second; + values are numbers")) + (let [expected "Goodbye!" + actual (parser/render "{% ifcontains record.roles :three %}Hello!{% else %}Goodbye!{% endifcontains %}" + {:option {:id 3 :name "Ginny"} :record {:roles [:two :six]}})] + (is (= expected actual) + "First arg is a path which exists in the context, second is a literal keyword; + the value of the first does not contain the value of the second; + values are numbers"))))