From 77647b8c4aaa7653df1fb83fa1f0071070d3f4da Mon Sep 17 00:00:00 2001
From: Cam Saul <cam@geotip.com>
Date: Wed, 1 Jul 2015 20:15:46 -0700
Subject: [PATCH] more work on nested field support

---
 src/metabase/driver/mongo.clj                 | 31 ++++++++-----------
 src/metabase/driver/mongo/query_processor.clj |  8 +++--
 src/metabase/driver/mongo/util.clj            |  3 --
 src/metabase/driver/sync.clj                  | 13 ++++----
 4 files changed, 24 insertions(+), 31 deletions(-)

diff --git a/src/metabase/driver/mongo.clj b/src/metabase/driver/mongo.clj
index 5987980f087..e4d70283f59 100644
--- a/src/metabase/driver/mongo.clj
+++ b/src/metabase/driver/mongo.clj
@@ -99,11 +99,8 @@
 
   ISyncDriverFieldSubFields
   (active-subfield-names->type [this field]
-    ;; shared part of driver should be enforcing this actually !
-    (assert (= (:base_type field) :UnknownField))
     ;; Build a map of nested-field-key -> type -> count
-    ;; TODO - using an atom isn't the *fastest* thing in the world (but is the easiest); this takes ~50ms for a smallish Field in the Geographic Tips dataset;
-    ;; if I run out of important things to do re-write this recursively or with transient collections
+    ;; TODO - using an atom isn't the *fastest* thing in the world (but is the easiest); consider alternate implementation
     (let [field->type->count (atom {})]
       ;; Look at the first 1000 values
       (doseq [val (take 1000 (field-values-lazy-seq this field))]
@@ -155,17 +152,15 @@
       (with-mongo-connection [_ db]
         (active-subfield-names->type driver &tips.venue)))))
 
-{:id        100
- :name      "address"
- :parent_id nil}
-
-{:parent_id    100
- :name         "street"
- :type         :CharField
- :special_type :name}
-
-{:name    "Tempest"
- :address {:street  "430 Natoma"
-           :city    "San Francisco"
-           :state   "CA"
-           :country "US"}}
+;; TODO
+;; 1. Sync
+;;    1A. Create new Field objects for each Nested Field during Sync
+;;    1B. Recursively call sync-field! for each nested field
+;; 2. QX
+;;    2A. Recursively resolve nested fields
+;;    2B. Add qualified-path-components fieldd to nested fields
+;; 3. Mongo
+;;    3A. Mongo QP handle nested Fields appropriately
+;; 4. API
+;;    4A. API Tweaks as Needed
+;; 5. Cleanup + Tests
diff --git a/src/metabase/driver/mongo/query_processor.clj b/src/metabase/driver/mongo/query_processor.clj
index ab540d770cc..7cd9fe88081 100644
--- a/src/metabase/driver/mongo/query_processor.clj
+++ b/src/metabase/driver/mongo/query_processor.clj
@@ -2,6 +2,7 @@
   (:refer-clojure :exclude [find sort])
   (:require [clojure.core.match :refer [match]]
             [clojure.tools.logging :as log]
+            [clojure.walk :as walk]
             [colorize.core :as color]
             (monger [collection :as mc]
                     [core :as mg]
@@ -38,9 +39,10 @@
       (case (keyword query-type)
         :query (let [generated-query (process-structured (:query query))]
                  (when-not qp/*disable-qp-logging*
-                   (log/debug (color/magenta "\n\n******************** Generated Monger Query: ********************\n"
-                                             (u/pprint-to-str generated-query)
-                                             "\n*****************************************************************\n")))
+                   (log/debug (u/format-color 'green "\nMONGER FORM:\n\n%s\n"
+                                              (->> generated-query
+                                                   (walk/postwalk #(if (symbol? %) (symbol (name %)) %)) ; strip namespace qualifiers from Monger form
+                                                   u/pprint-to-str) "\n")))                              ; so it's easier to read
                  {:results (eval generated-query)})
         :native (let [results (eval-raw-command (:query (:native query)))]
                   {:results (if (sequential? results) results
diff --git a/src/metabase/driver/mongo/util.clj b/src/metabase/driver/mongo/util.clj
index 46cee85ce8d..142a950efab 100644
--- a/src/metabase/driver/mongo/util.clj
+++ b/src/metabase/driver/mongo/util.clj
@@ -93,8 +93,5 @@
            (sort-by second)
            first
            first
-           ((fn [v]
-              (println (metabase.util/format-color 'green "TYPE: %s" v))
-              v))
            driver/class->base-type)
       :UnknownField))
diff --git a/src/metabase/driver/sync.clj b/src/metabase/driver/sync.clj
index 4d6effbf4a6..de312f2b5a4 100644
--- a/src/metabase/driver/sync.clj
+++ b/src/metabase/driver/sync.clj
@@ -24,7 +24,7 @@
          sync-table-active-fields-and-pks!
          sync-table-fks!
          sync-table-fields-metadata!
-         update-field-subfields!
+         sync-field-subfields!
          update-table-row-count!)
 
 ;; ## sync-database! and sync-table!
@@ -152,7 +152,7 @@
     ;; Now do the syncing for Table's Fields
     (log/debug (format "Determining active Fields for Table '%s'..." (:name table)))
     (let [active-column-names->type (active-column-names->type driver table)
-          field-name->id (sel :many :field->id [Field :name] :table_id (:id table) :active true)]
+          field-name->id            (sel :many :field->id [Field :name] :table_id (:id table) :active true)]
       (assert (map? active-column-names->type) "active-column-names->type should return a map.")
       (assert (every? string? (keys active-column-names->type)) "The keys of active-column-names->type should be strings.")
       (assert (every? (partial contains? field/base-types) (vals active-column-names->type)) "The vals of active-column-names->type should be valid Field base types.")
@@ -246,13 +246,12 @@
   {:pre [driver
          field]}
   (log/debug (format "Syncing field '%s.%s'..." (:name @(:table field)) (:name field)))
-  (println (u/format-color 'red "FIELD TYPE: %s" field))
   (sync-field->> field
                  (mark-url-field! driver)
                  mark-category-field!
                  (mark-no-preview-display-field! driver)
                  auto-assign-field-special-type-by-name!
-                 (update-field-subfields! driver)))
+                 (sync-field-subfields! driver)))
 
 
 ;; Each field-syncing function below should return FIELD with any updates that we made, or nil.
@@ -429,9 +428,9 @@
       (assoc field :special_type special-type))))
 
 
-(defn- update-field-subfields! [driver field]
-  (when (and (= (:base_type field) :UnknownField)
+(defn- sync-field-subfields! [driver field]
+  (when (and (= (:base_type field) :DictionaryField)
              (supports? driver :nested-fields)              ; if one of these is true
              (satisfies? ISyncDriverFieldSubFields driver)) ; the other should be :wink:
     (let [subfield-name->type (active-subfield-names->type driver field)]
-      (log/info "Syncing subfields for '%s.%s': %s"  (:name @(:table field)) (:name field) (keys subfield-name->type)))))
+      (log/info (u/format-color 'green "Syncing subfields for '%s.%s': %s"  (:name @(:table field)) (:name field) (keys subfield-name->type))))))
-- 
GitLab