diff --git a/src/metabase/api/card.clj b/src/metabase/api/card.clj
index fc9cf849ab7faf1a2edd506f3eb2b8fd40253e9d..50b64842fd682a1f979ace15cf879365581101f8 100644
--- a/src/metabase/api/card.clj
+++ b/src/metabase/api/card.clj
@@ -564,7 +564,7 @@
         ttl   (when (public-settings/enable-query-caching)
                 (or (:cache_ttl card)
                     (query-magic-ttl query)))]
-    (assoc query :cache_ttl ttl)))
+    (assoc query :cache-ttl ttl)))
 
 (defn run-query-for-card
   "Run the query for Card with PARAMETERS and CONSTRAINTS, and return results in the usual format."
diff --git a/src/metabase/automagic_dashboards/core.clj b/src/metabase/automagic_dashboards/core.clj
index 4ad7cc6d871e9571b5304fd531549e356e2a9e8d..d0173fcc9ed3a79c96fcb79992fc8ab86595c50d 100644
--- a/src/metabase/automagic_dashboards/core.clj
+++ b/src/metabase/automagic_dashboards/core.clj
@@ -35,7 +35,7 @@
              [query :refer [Query]]
              [segment :refer [Segment]]
              [table :refer [Table]]]
-            [metabase.query-processor.middleware.expand-macros :as qp.expand]
+            [metabase.query-processor.middleware.expand-macros :as qp.macros]
             [metabase.query-processor.util :as qp.util]
             [metabase.sync.analyze.classify :as classify]
             [metabase.util.date :as date]
@@ -82,7 +82,7 @@
 
 (def ^:private ^{:arglists '([metric])} saved-metric?
   (every-pred (partial mbql.u/is-clause? :metric)
-              (complement qp.expand/ga-metric?)))
+              (complement qp.macros/ga-metric-or-segment?)))
 
 (def ^:private ^{:arglists '([metric])} custom-expression?
   (partial mbql.u/is-clause? :named))
@@ -94,10 +94,10 @@
   "Return the name of the metric or name by describing it."
   [[op & args :as metric]]
   (cond
-    (qp.expand/ga-metric? metric) (-> args first str (subs 3) str/capitalize)
-    (adhoc-metric? metric)        (-> op qp.util/normalize-token op->name)
-    (saved-metric? metric)        (-> args first Metric :name)
-    :else                         (second args)))
+    (qp.macros/ga-metric-or-segment? metric) (-> args first str (subs 3) str/capitalize)
+    (adhoc-metric? metric)                   (-> op qp.util/normalize-token op->name)
+    (saved-metric? metric)                   (-> args first Metric :name)
+    :else                                    (second args)))
 
 (defn metric-op
   "Return the name op of the metric"
diff --git a/src/metabase/mbql/normalize.clj b/src/metabase/mbql/normalize.clj
index 313f6cba0c4f96c7212cda7ba9a8e87e3148945d..2360ada24d7bf024cff2182a395fa5b72731b334 100644
--- a/src/metabase/mbql/normalize.clj
+++ b/src/metabase/mbql/normalize.clj
@@ -297,9 +297,8 @@
         (cond-> arg
           (mbql-clause? arg) canonicalize-aggregation-subclause))))
 
-    ;; for metric and segment macros (e.g. [:metric <metric-id>]) do not wrap the metric/segment ID in a :field-id
-    ;; clause
-    (#{:metric :segment} ag-type)
+    ;; for metric macros (e.g. [:metric <metric-id>]) do not wrap the metric in a :field-id clause
+    (= :metric ag-type)
     ag-subclause
 
     ;; something with an arg like [:sum [:field-id 41]]
diff --git a/src/metabase/mbql/schema.clj b/src/metabase/mbql/schema.clj
index 0394770a66eef31bcc667402c93e06b8fd9695c1..d249df9fd4e7a984edeeffc41645ff4de1f7df7e 100644
--- a/src/metabase/mbql/schema.clj
+++ b/src/metabase/mbql/schema.clj
@@ -296,7 +296,10 @@
 
 ;; A segment is a special `macro` that saves some pre-definied filter clause, e.g. [:segment 1]
 ;; this gets replaced by a normal Filter clause in MBQL macroexpansion
-(defclause segment, segment-id su/IntGreaterThanZero)
+;;
+;; It can also be used for GA, which looks something like `[:segment "gaid::-11"]`. GA segments aren't actually MBQL
+;; segments and pass-thru to GA.
+(defclause segment, segment-id (s/cond-pre su/IntGreaterThanZero su/NonBlankString))
 
 (def Filter
   "Schema for a valid MBQL `:filter` clause."
@@ -319,7 +322,9 @@
 (def ^:private NativeQuery
   "Schema for a valid, normalized native [inner] query."
   {:query                          s/Any
-   (s/optional-key :template-tags) {su/NonBlankString TemplateTag}})
+   (s/optional-key :template-tags) {su/NonBlankString TemplateTag}
+   ;; collection (table) this query should run against. Needed for MongoDB
+   (s/optional-key :collection)    (s/maybe su/NonBlankString)})
 
 
 ;;; ----------------------------------------------- MBQL [Inner] Query -----------------------------------------------
@@ -453,6 +458,10 @@
     (s/optional-key :settings)    (s/maybe Settings)
     (s/optional-key :constraints) (s/maybe Constraints)
     (s/optional-key :middleware)  (s/maybe MiddlewareOptions)
+    ;; The maximum time, in seconds, to return cached results for this query rather than running a new query. This is
+    ;; added automatically when running queries belonging to Cards when caching is enabled. Caching is handled by the
+    ;; automatically by caching middleware.
+    (s/optional-key :cache-ttl)   (s/maybe su/IntGreaterThanZero)
     ;;
     ;; -------------------- INFO --------------------
     ;;
diff --git a/src/metabase/query_processor/middleware/cache.clj b/src/metabase/query_processor/middleware/cache.clj
index 58b088a3414e9e15de0a3f666f58fb683650f9fe..471040a384a71c5d646d7c8c27ddfd0c85ef310b 100644
--- a/src/metabase/query_processor/middleware/cache.clj
+++ b/src/metabase/query_processor/middleware/cache.clj
@@ -85,7 +85,7 @@
 
 ;;; --------------------------------------------------- Middleware ---------------------------------------------------
 
-(defn- is-cacheable? ^Boolean [{cache-ttl :cache_ttl}]
+(defn- is-cacheable? ^Boolean [{:keys [cache-ttl]}]
   (boolean (and (public-settings/enable-query-caching)
                 cache-ttl)))
 
@@ -121,7 +121,7 @@
       (save-results-if-successful! query-hash results))
     results))
 
-(defn- run-query-with-cache [qp {cache-ttl :cache_ttl, :as query}]
+(defn- run-query-with-cache [qp {:keys [cache-ttl], :as query}]
   ;; TODO - Query should already have a `info.hash`, shouldn't it?
   (let [query-hash (qputil/query-hash query)]
     (or (cached-results query-hash cache-ttl)
@@ -133,7 +133,7 @@
   In order for a query to be eligible for caching:
 
      *  Caching (the `enable-query-caching` Setting) must be enabled
-     *  The query must pass a `:cache_ttl` value. For Cards, this can be the value of `:cache_ttl`,
+     *  The query must pass a `:cache-ttl` value. For Cards, this can be the value of `:cache_ttl`,
         otherwise falling back to the value of the `query-caching-default-ttl` Setting.
      *  The query must already be permissions-checked. Since the cache bypasses the normal
         query processor pipeline, the ad-hoc permissions-checking middleware isn't applied for cached results.
diff --git a/src/metabase/query_processor/middleware/expand_macros.clj b/src/metabase/query_processor/middleware/expand_macros.clj
index 524d0b550e59445940ccb7c83d69e471dfd41edd..acdb06333142fe18363ebb0d4c9fa503fc76bf3c 100644
--- a/src/metabase/query_processor/middleware/expand_macros.clj
+++ b/src/metabase/query_processor/middleware/expand_macros.clj
@@ -1,9 +1,8 @@
 (ns metabase.query-processor.middleware.expand-macros
-  "Middleware for expanding `METRIC` and `SEGMENT` 'macros' in *unexpanded* MBQL queries.
+  "Middleware for expanding `:metric` and `:segment` 'macros' in *unexpanded* MBQL queries.
 
-   Code in charge of expanding [\"METRIC\" ...] and [\"SEGMENT\" ...] forms in MBQL queries.
-   (METRIC forms are expanded into aggregations and sometimes filter clauses, while SEGMENT forms
-    are expanded into filter clauses.)
+  (`:metric` forms are expanded into aggregations and sometimes filter clauses, while `:segment` forms are expanded
+  into filter clauses.)
 
    TODO - this namespace is ancient and written with MBQL '95 in mind, e.g. it is case-sensitive.
    At some point this ought to be reworked to be case-insensitive and cleaned up."
@@ -19,18 +18,31 @@
             [puppetlabs.i18n.core :refer [tru]]
             [toucan.db :as db]))
 
+(defn ga-metric-or-segment?
+  "Is this metric or segment clause not a Metabase Metric or Segment, but rather a GA one? E.g. something like `[:metric
+  ga:users]`. We want to ignore those because they're not the same thing at all as MB Metrics/Segments and don't
+  correspond to objects in our application DB."
+  [[_ id]]
+  (boolean
+   (when ((some-fn string? keyword?) id)
+     (re-find #"^ga(id)?:" (name id)))))
+
+
 ;;; +----------------------------------------------------------------------------------------------------------------+
 ;;; |                                                    SEGMENTS                                                    |
 ;;; +----------------------------------------------------------------------------------------------------------------+
 
 (defn- segment-clauses->id->definition [segment-clauses]
-  (db/select-id->field :definition Segment, :id [:in (set (map second segment-clauses))]))
+  (when-let [segment-ids (seq (filter integer? (map second segment-clauses)))]
+    (db/select-id->field :definition Segment, :id [:in (set segment-ids)])))
 
 (defn- replace-segment-clauses [outer-query segment-id->definition]
   (mbql.u/replace-clauses-in outer-query [:query] :segment
-    (fn [[_ segment-id]]
-      (or (:filter (segment-id->definition segment-id))
-          (throw (IllegalArgumentException. (str (tru "Segment {0} does not exist, or is invalid." segment-id))))))))
+    (fn [[_ segment-id, :as segment]]
+      (if (ga-metric-or-segment? segment)
+        segment
+        (or (:filter (segment-id->definition segment-id))
+            (throw (IllegalArgumentException. (str (tru "Segment {0} does not exist, or is invalid." segment-id)))))))))
 
 (defn- expand-segments [{inner-query :query, :as outer-query}]
   (if-let [segments (mbql.u/clause-instances :segment inner-query)]
@@ -42,19 +54,10 @@
 ;;; |                                                    METRICS                                                     |
 ;;; +----------------------------------------------------------------------------------------------------------------+
 
-(defn ga-metric?
-  "Is this metric clause not a Metabase Metric, but rather a GA one? E.g. something like [metric ga:users]. We want to
-   ignore those because they're not the same thing at all as MB Metrics and don't correspond to objects in our
-   application DB."
-  [[_ id]]
-  (boolean
-   (when ((some-fn string? keyword?) id)
-     (re-find #"^ga(id)?:" (name id)))))
-
 (defn- metrics
   "Return a sequence of any (non-GA) `:metric` MBQL clauses in `query`."
   [{inner-query :query}] ; metrics won't be in a native query but they could be in source-query or aggregation clause
-  (seq (filter (complement ga-metric?) (mbql.u/clause-instances :metric inner-query))))
+  (seq (filter (complement ga-metric-or-segment?) (mbql.u/clause-instances :metric inner-query))))
 
 (defn- metric-clauses->id->definition [metric-clauses]
   (db/select-id->field :definition Metric, :id [:in (set (map second metric-clauses))]))
@@ -66,7 +69,7 @@
 (defn- replace-metrics-aggregations [query metric-id->definition]
   (mbql.u/replace-clauses-in query [:query] :metric
     (fn [[_ metric-id, :as metric]]
-      (if (ga-metric? metric)
+      (if (ga-metric-or-segment? metric)
         metric
         (or (first (:aggregation (metric-id->definition metric-id)))
             (throw (IllegalArgumentException.
diff --git a/test/metabase/mbql/normalize_test.clj b/test/metabase/mbql/normalize_test.clj
index b8bd055d1175a96a17d19b1b4d9eef558b8f602a..215f708d608012e31290aa3d1a6a4ae0a3757a03 100644
--- a/test/metabase/mbql/normalize_test.clj
+++ b/test/metabase/mbql/normalize_test.clj
@@ -519,6 +519,21 @@
     :type     :query
     :query    {:filter []}}))
 
+;; make sure we can handle GA segments
+(expect
+  {:database 1,
+   :type     :query
+   :query    {:filter
+              [:and
+               [:segment "gaid:-11"]
+               [:time-interval [:field-id 6851] -365 :day {}]]}}
+  (#'normalize/canonicalize
+   {:database 1
+    :type     :query
+    :query    {:filter [:and
+                        [:segment "gaid:-11"]
+                        [:time-interval [:field-id 6851] -365 :day {}]]}}))
+
 ;; ORDER BY: MBQL 95 [field direction] should get translated to MBQL 98 [direction field]
 (expect
   {:query {:order-by [[:asc [:field-id 10]]]}}
@@ -711,6 +726,7 @@
                                                            :required     true
                                                            :default      "Widget"}}}}}))
 
+;; make sure `rows` queries get removed
 (expect
   {:database 4,
    :type     :query,
diff --git a/test/metabase/query_processor/middleware/cache_test.clj b/test/metabase/query_processor/middleware/cache_test.clj
index 5b51cf02b06a36c4196ec3c60dbd06d2aca87db5..905f92d8f293c7cd84c1a186579f51d3729dbf31 100644
--- a/test/metabase/query_processor/middleware/cache_test.clj
+++ b/test/metabase/query_processor/middleware/cache_test.clj
@@ -34,7 +34,7 @@
     :not-cached))
 
 (defn- run-query [& {:as query-kvs}]
-  (cached? (maybe-return-cached-results (merge {:cache_ttl 60, :query :abc} query-kvs))))
+  (cached? (maybe-return-cached-results (merge {:cache-ttl 60, :query :abc} query-kvs))))
 
 
 ;;; -------------------------------------------- tests for is-cacheable? ---------------------------------------------
@@ -42,17 +42,17 @@
 ;; something is-cacheable? if it includes a cach_ttl and the caching setting is enabled
 (expect
   (tu/with-temporary-setting-values [enable-query-caching true]
-    (#'cache/is-cacheable? {:cache_ttl 100})))
+    (#'cache/is-cacheable? {:cache-ttl 100})))
 
 (expect
   false
   (tu/with-temporary-setting-values [enable-query-caching false]
-    (#'cache/is-cacheable? {:cache_ttl 100})))
+    (#'cache/is-cacheable? {:cache-ttl 100})))
 
 (expect
   false
   (tu/with-temporary-setting-values [enable-query-caching true]
-    (#'cache/is-cacheable? {:cache_ttl nil})))
+    (#'cache/is-cacheable? {:cache-ttl nil})))
 
 
 ;;; ------------------------------------- results-are-below-max-byte-threshold? --------------------------------------
@@ -104,9 +104,9 @@
   (tu/with-temporary-setting-values [enable-query-caching  true
                                      query-caching-min-ttl 0]
     (clear-cache!)
-    (run-query :cache_ttl 1)
+    (run-query :cache-ttl 1)
     (Thread/sleep 2000)
-    (run-query :cache_ttl 1)))
+    (run-query :cache-ttl 1)))
 
 ;; if caching is disabled then cache shouldn't be used even if there's something valid in there
 (expect
diff --git a/test/metabase/query_processor/middleware/expand_macros_test.clj b/test/metabase/query_processor/middleware/expand_macros_test.clj
index d5f295bcaedb1e324e708dce6eac743cb94a72a7..05c1199f9a5db7ba6bcf98df9134d62cdcd05cc9 100644
--- a/test/metabase/query_processor/middleware/expand_macros_test.clj
+++ b/test/metabase/query_processor/middleware/expand_macros_test.clj
@@ -177,23 +177,36 @@
                           :aggregation  [[:metric (u/get-id metric)]]
                           :breakout     [[:field-id (data/id :venues :price)]]}})))))
 
+(defn- mbql-query [inner-query]
+  {:database 1, :type :query, :query inner-query})
+
 ;; make sure that we don't try to expand GA "metrics" (#6104)
 (expect
-  {:query {:aggregation [[:metric :ga:users]]}}
-  (#'expand-macros/expand-metrics-and-segments {:query {:aggregation [[:metric :ga:users]]}}))
+  (mbql-query {:aggregation [[:metric "ga:users"]]})
+  (#'expand-macros/expand-metrics-and-segments (mbql-query {:aggregation [[:metric "ga:users"]]})))
 
 (expect
-  {:query {:aggregation [[:metric :gaid:users]]}}
-  (#'expand-macros/expand-metrics-and-segments {:query {:aggregation [[:metric :gaid:users]]}}))
+  (mbql-query {:aggregation [[:metric "gaid:users"]]})
+  (#'expand-macros/expand-metrics-and-segments (mbql-query {:aggregation [[:metric "gaid:users"]]})))
 
 ;; make sure expansion works with multiple GA "metrics" (#7399)
 (expect
-  {:query {:aggregation [[:metric :ga:users] [:metric :ga:1dayUsers]]}}
-  (#'expand-macros/expand-metrics-and-segments {:query {:aggregation [[:metric :ga:users] [:metric :ga:1dayUsers]]}}))
+  (mbql-query {:aggregation [[:metric "ga:users"]
+                             [:metric "ga:1dayUsers"]]})
+  (#'expand-macros/expand-metrics-and-segments (mbql-query {:aggregation [[:metric "ga:users"]
+                                                                          [:metric "ga:1dayUsers"]]})))
+
+;; make sure we don't try to expand GA "segments"
+(expect
+  (mbql-query {:filter [:segment "gaid:-11"]})
+  (#'expand-macros/expand-metrics-and-segments (mbql-query {:filter [:segment "gaid:-11"]})))
 
 ;; make sure we can name a :metric (ick)
 (expect
+  (mbql-query
+   {:aggregation [[:named [:sum [:field-id 20]] "My Cool Metric"]]
+    :breakout    [[:field-id 10]]})
   (tt/with-temp Metric [metric {:definition {:aggregation [[:sum [:field-id 20]]]}}]
     (#'expand-macros/expand-metrics-and-segments
-     {:query {:aggregation [[:named [:metric (u/get-id metric)] "My Cool Metric"]]
-              :breakout    [[:field-id 10]]}})))
+     (mbql-query {:aggregation [[:named [:metric (u/get-id metric)] "My Cool Metric"]]
+                  :breakout    [[:field-id 10]]}))))