From 40fc3a99cc653c855331c3fe3f0b46d5dff2c296 Mon Sep 17 00:00:00 2001
From: Simon Brooke <simon@journeyman.cc>
Date: Sat, 16 Jun 2018 10:34:05 +0100
Subject: [PATCH 1/2] Added drill-down in lists.

---
 src/adl/to_psql.clj             | 110 +++++++++++++++++---------------
 src/adl/to_selmer_templates.clj |  43 +++++++++----
 2 files changed, 88 insertions(+), 65 deletions(-)

diff --git a/src/adl/to_psql.clj b/src/adl/to_psql.clj
index dd4dcf1..faf2b21 100644
--- a/src/adl/to_psql.clj
+++ b/src/adl/to_psql.clj
@@ -281,7 +281,8 @@
     " ||', '|| "
     (compose-convenience-entity-field field entity application))
    " AS "
-   (field-name field)))
+   (field-name field)
+    "_expanded"))
 
 
 (defn emit-convenience-view
@@ -290,59 +291,62 @@
   [entity application]
   (let [view-name (safe-name (str "lv_" (:table (:attrs entity))) :sql)
         entity-fields (filter
-                       #(= (:type (:attrs %)) "entity")
-                       (properties entity))]
+                        #(= (:type (:attrs %)) "entity")
+                        (properties entity))]
     (s/join
-     "\n"
-     (remove
-      nil?
-      (flatten
-       (list
-        (emit-header
-         "--"
-         (str "convenience view " view-name " of entity " (:name (:attrs entity)) " for lists, et cetera"))
-        (s/join
-         " "
-         (list "CREATE VIEW" view-name "AS"))
-        (str
-         "SELECT "
-         (s/join
-          ",\n\t"
-          (map
-           #(if
-              (= (:type (:attrs %)) "entity")
-              (emit-convenience-entity-field % entity application)
-              (str (safe-name entity) "." (field-name %)))
-           (filter
-            #(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))
-          (str
-           "WHERE "
-           (s/join
-            "\n\tAND "
-            (map
-             (fn [f]
-               (let
-                 [farside (child
-                           application
-                           #(and
-                             (entity? %)
-                             (= (:name (:attrs %)) (:entity (:attrs f)))))]
-                 (str
-                  (safe-name (:table (:attrs entity)) :sql)
-                  "."
-                  (field-name f)
-                  " = "
-                  (safe-name (:table (:attrs farside)) :sql)
-                  "."
-                  (safe-name (first (key-names farside)) :sql))))
-             entity-fields))))
-        ";"
-        (emit-permissions-grant view-name :SELECT (permissions entity application))))))))
+      "\n"
+      (remove
+        nil?
+        (flatten
+          (list
+            (emit-header
+              "--"
+              (str "convenience view " view-name " of entity " (:name (:attrs entity)) " for lists, et cetera"))
+            (s/join
+              " "
+              (list "CREATE VIEW" view-name "AS"))
+            (str
+              "SELECT "
+              (s/join
+                ",\n\t"
+                (flatten
+                  (map
+                    #(if
+                       (= (:type (:attrs %)) "entity")
+                       (list
+                         (emit-convenience-entity-field % entity application)
+                         (str (safe-name entity) "." (field-name %)))
+                       (str (safe-name entity) "." (field-name %)))
+                    (filter
+                      #(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))
+              (str
+                "WHERE "
+                (s/join
+                  "\n\tAND "
+                  (map
+                    (fn [f]
+                      (let
+                        [farside (child
+                                   application
+                                   #(and
+                                      (entity? %)
+                                      (= (:name (:attrs %)) (:entity (:attrs f)))))]
+                        (str
+                          (safe-name (:table (:attrs entity)) :sql)
+                          "."
+                          (field-name f)
+                          " = "
+                          (safe-name (:table (:attrs farside)) :sql)
+                          "."
+                          (safe-name (first (key-names farside)) :sql))))
+                    entity-fields))))
+            ";"
+            (emit-permissions-grant view-name :SELECT (permissions entity application))))))))
 
 
 (defn emit-referential-integrity-link
diff --git a/src/adl/to_selmer_templates.clj b/src/adl/to_selmer_templates.clj
index 69faf38..a813092 100644
--- a/src/adl/to_selmer_templates.clj
+++ b/src/adl/to_selmer_templates.clj
@@ -362,6 +362,7 @@
   taken from this `application`. If `page` is nil, generate a default page
   template for the entity."
   [page entity application]
+  ;; TODO
   )
 
 
@@ -416,7 +417,21 @@
                      :value "Search"}}]})))}]})
 
 
-(defn- list-tbody
+(defn edit-link
+  [entity application parameters]
+  (str
+    (editor-name entity application)
+    "?"
+    (s/join
+      "&amp;"
+      (map
+        #(let [n (:name (:attrs %1))]
+           (str n "={{ record." %2 " }}"))
+        (key-names entity)
+        parameters))))
+
+
+(defn list-tbody
   "Return a table body element for the list view for this `list-spec` of this `entity` within
   this `application`."
   [list-spec entity application]
@@ -430,22 +445,26 @@
        (concat
          (map
            (fn [field]
-             {:tag :td :content [(str "{{ record." (:property (:attrs field)) " }}")]})
+             {:tag :td :content
+              (let
+               [p (first (filter #(= (:name (:attrs %)) (:property (:attrs field))) (all-properties entity)))
+                e (first
+                    (filter
+                      #(= (:name (:attrs %)) (:entity (:attrs p)))
+                      (children-with-tag application :entity)))
+                c (str "{{ record." (:property (:attrs field)) " }}")]
+               (if
+                 (= (:type (:attrs p)) "entity")
+                 [{:tag :a
+                   :attrs {:href (edit-link e application (list (:name (:attrs p))))}
+                   :content [(str "{{ record." (:property (:attrs field)) "_expanded }}")]}]
+                 [c]))})
            (fields list-spec))
          [{:tag :td
           :content
           [{:tag :a
      :attrs
-     {:href
-      (str
-        (editor-name entity application)
-        "?"
-        (s/join
-          "&amp;"
-          (map
-            #(let [n (:name (:attrs %))]
-               (str n "={{ record." n "}}"))
-            (children (first (filter #(= (:tag %) :key) (children entity)))))))}
+     {:href (edit-link entity application (key-names entity))}
      :content ["View"]}]}]))}
     "{% endfor %}"]})
 

From adca71875cd639dec6edbc13516af4cefd43e147 Mon Sep 17 00:00:00 2001
From: Simon Brooke <simon@journeyman.cc>
Date: Sat, 16 Jun 2018 11:29:21 +0100
Subject: [PATCH 2/2] Work on getting forms working. Not complete but a
 considerable advance.

---
 src/adl/to_selmer_routes.clj    |  9 ++++-
 src/adl/to_selmer_templates.clj | 72 ++++++++++++++++++---------------
 2 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/src/adl/to_selmer_routes.clj b/src/adl/to_selmer_routes.clj
index 597797a..62170c1 100644
--- a/src/adl/to_selmer_routes.clj
+++ b/src/adl/to_selmer_routes.clj
@@ -61,7 +61,10 @@
       'defn
       (symbol n)
       (vector 'r)
-      (list 'let (vector 'p (list :form-params 'r))
+      (list 'let (vector 'p (list :params 'r)) ;; TODO: we must take key params out of just params,
+            ;; but we should take all other params out of form-params - because we need the key to
+            ;; load the form in the first place, but just accepting values of other params would
+            ;; allow spoofing.
             (list
               'l/render
               (list 'resolve-template (str n ".html"))
@@ -71,10 +74,12 @@
                 (case (:tag f)
                   (:form :page)
                   {:record
+                   (list 'if (list 'empty? (list 'remove 'nil? (list 'vals 'p))) []
                    (list
                      (symbol
                        (str "db/get-" (singularise (:name (:attrs e)))))
-                     'p)}
+                       (symbol "db/*db*")
+                     'p))}
                   :list
                   {:records
                    (list
diff --git a/src/adl/to_selmer_templates.clj b/src/adl/to_selmer_templates.clj
index a813092..b784f9b 100644
--- a/src/adl/to_selmer_templates.clj
+++ b/src/adl/to_selmer_templates.clj
@@ -366,12 +366,36 @@
   )
 
 
+(defn compose-list-search-widget
+  [field entity]
+  (let [property (first
+                   (children
+                     entity
+                     (fn [p] (and (= (:tag p) :property)
+                                  (= (:name (:attrs p)) (:property (:attrs field)))))))
+        input-type (case (:type (:attrs property))
+                     ("integer" "real" "money") "number"
+                     ("date" "timestamp") "date"
+                     "time" "time"
+                     "text")
+        base-name (:property (:attrs field))
+        search-name (if
+                      (= (:type (:attrs property)) "entity")
+                      (str base-name "_expanded") base-name)]
+    (hash-map
+      :tag :th
+      :content
+      [{:tag :input
+        :attrs {:id search-name
+                :type input-type
+                :name search-name
+                :value (str "{{ params." search-name " }}")}}])))
+
+
+
 (defn- list-thead
   "Return a table head element for the list view for this `list-spec` of this `entity` within
-  this `application`.
-
-  TODO: where entity fields are being shown/searched on, we should be using the user-distinct
-  fields of the far side, rather than key values"
+  this `application`."
   [list-spec entity application]
   {:tag :thead
    :content
@@ -388,33 +412,16 @@
      :content
      (apply
        vector
-      (concat
-       (map
-         (fn [f]
-           (let [property (first
-                            (children
-                              entity
-                              (fn [p] (and (= (:tag p) :property)
-                                           (= (:name (:attrs p)) (:property (:attrs f)))))))]
-             (hash-map
-               :tag :th
-               :content
-               [{:tag :input
-                 :attrs {:id (:property (:attrs f))
-                         :type (case (:type (:attrs property))
-                         ("integer" "real" "money") "number"
-                         ("date" "timestamp") "date"
-                         "time" "time"
-                         "text")
-                         :name (:property (:attrs f))
-                         :value (str "{{ params." (:property (:attrs f)) " }}")}}])))
-         (fields list-spec))
-        '({:tag :th
-           :content
-           [{:tag :input
-             :attrs {:type "submit"
-                     :id "search"
-                     :value "Search"}}]})))}]})
+       (concat
+         (map
+           #(compose-list-search-widget % entity)
+           (fields list-spec))
+         '({:tag :th
+            :content
+            [{:tag :input
+              :attrs {:type "submit"
+                      :id "search"
+                      :value "Search"}}]})))}]})
 
 
 (defn edit-link
@@ -425,8 +432,7 @@
     (s/join
       "&amp;"
       (map
-        #(let [n (:name (:attrs %1))]
-           (str n "={{ record." %2 " }}"))
+        #(str %1 "={{ record." %2 " }}")
         (key-names entity)
         parameters))))