From 79b08ee8627ad2b3d4d7703e9aeb1a48db5d3493 Mon Sep 17 00:00:00 2001 From: Cam Saul <1455846+camsaul@users.noreply.github.com> Date: Wed, 1 Feb 2023 13:56:25 -0800 Subject: [PATCH] Switch Audit App to Honey SQL 2. Add `hx/call` and `hx/raw` (#27975) * Switch Audit App to Honey SQL 2 * Compile using Honey SQL 2 * Mark some more tests as ^:parallel * Remove unused namespace * Backport sql.qp/current-datetime-honeysql-form :mysql Honey SQL 2 support * Add `hx/call` and `hx/raw` * Update enterprise/backend/src/metabase_enterprise/audit_app/pages/common.clj Co-authored-by: metamben <103100869+metamben@users.noreply.github.com> * `#schema` => `#hawk/schema` * Mark `metabase.async.streaming-response-test` as `^:mb/once` --------- Co-authored-by: metamben <103100869+metamben@users.noreply.github.com> --- .clj-kondo/config.edn | 2 + .../audit_app/pages/alerts.clj | 4 +- .../audit_app/pages/common.clj | 102 ++++++++------- .../common/card_and_dashboard_detail.clj | 24 ++-- .../audit_app/pages/common/cards.clj | 12 +- .../audit_app/pages/common/dashboards.clj | 96 +++++++------- .../audit_app/pages/common/pulses.clj | 4 +- .../audit_app/pages/dashboard_detail.clj | 2 +- .../pages/dashboard_subscriptions.clj | 4 +- .../audit_app/pages/dashboards.clj | 16 +-- .../audit_app/pages/databases.clj | 12 +- .../audit_app/pages/downloads.clj | 29 ++--- .../audit_app/pages/queries.clj | 102 +++++++-------- .../audit_app/pages/query_detail.clj | 3 +- .../audit_app/pages/schemas.clj | 10 +- .../audit_app/pages/tables.clj | 12 +- .../audit_app/pages/user_detail.clj | 37 +++--- .../audit_app/pages/users.clj | 51 ++++---- .../audit_app/pages/common_test.clj | 64 +++++----- .../row_level_restrictions_test.clj | 52 ++++---- .../athena/src/metabase/driver/athena.clj | 55 ++++---- .../test/metabase/driver/athena_test.clj | 27 ++-- .../bigquery_cloud_sdk/query_processor.clj | 53 ++++---- .../query_processor_test.clj | 63 +++++----- .../oracle/src/metabase/driver/oracle.clj | 79 ++++++------ .../test/metabase/driver/oracle_test.clj | 67 +++++----- .../src/metabase/driver/presto_common.clj | 72 +++++------ .../src/metabase/driver/presto_jdbc.clj | 117 +++++++++--------- .../test/metabase/driver/presto_jdbc_test.clj | 50 ++++---- .../test/metabase/driver/presto_test.clj | 43 +++---- .../redshift/src/metabase/driver/redshift.clj | 90 +++++++------- .../src/metabase/driver/snowflake.clj | 53 ++++---- .../src/metabase/driver/hive_like.clj | 111 +++++++++-------- .../sparksql/src/metabase/driver/sparksql.clj | 50 ++++---- .../sqlite/src/metabase/driver/sqlite.clj | 108 ++++++++-------- .../src/metabase/driver/sqlserver.clj | 99 +++++++-------- .../vertica/src/metabase/driver/vertica.clj | 104 ++++++++-------- src/metabase/driver/h2.clj | 30 ++--- src/metabase/driver/mysql.clj | 54 ++++---- src/metabase/driver/postgres.clj | 33 +++-- src/metabase/driver/sql/query_processor.clj | 90 +++++++------- src/metabase/models/collection.clj | 3 +- src/metabase/models/setting/cache.clj | 3 +- src/metabase/models/table.clj | 12 +- src/metabase/server/middleware/session.clj | 4 +- src/metabase/util/honey_sql_1_extensions.clj | 32 +++-- src/metabase/util/honeysql_extensions.clj | 19 +++ .../async/streaming_response_test.clj | 2 +- test/metabase/driver/h2_test.clj | 17 ++- test/metabase/driver/postgres_test.clj | 110 ++++++++-------- .../driver/sql/query_processor_test.clj | 18 +-- test/metabase/models/setting/cache_test.clj | 14 +-- .../nested_queries_test.clj | 25 ++-- .../query_processor_test/timezones_test.clj | 9 +- 54 files changed, 1205 insertions(+), 1149 deletions(-) diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index 8f3a10c8a87..430f209a799 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -85,6 +85,8 @@ :discouraged-var {clojure.string/lower-case {:message "Use metabase.util/lower-case-en instead of clojure.string/lower-case"} clojure.string/upper-case {:message "Use metabase.util/upper-case-en instead of clojure.string/upper-case"} + honeysql.core/call {:message "Use hx/call instead because it is Honey SQL 2 friendly"} + honeysql.core/raw {:message "Use hx/raw instead because it is Honey SQL 2 friendly"} toucan.db/query {:message "Use mdb.query/query instead of toucan.db/query"} toucan.db/reducible-query {:message "Use mdb.query/reducible-query instead of toucan.db/reducible-query"}} diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/alerts.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/alerts.clj index e85ae70eedc..4a729689855 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/alerts.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/alerts.clj @@ -35,8 +35,8 @@ ;; if `pulse.alert_condition` is non-NULL then the Pulse is an Alert [:not= :pulse.alert_condition nil] (when-not (str/blank? card-name) - [:like :%lower.card.name (str \% (u/lower-case-en card-name) \%)])]))) - (assoc :order-by [[:%lower.card.name :asc] + [:like [:lower :card.name] (str \% (u/lower-case-en card-name) \%)])]))) + (assoc :order-by [[[:lower :card.name] :asc] ;; Newest first. ID instead of `created_at` because the column is currently only ;; second-resolution for MySQL which busts our tests [:channel.id :desc]]))) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common.clj index a52b062415c..10f88eb84a2 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common.clj @@ -4,12 +4,12 @@ [clojure.core.async :as a] [clojure.core.memoize :as memoize] [clojure.walk :as walk] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [honeysql.helpers :as hh] + [honey.sql :as sql] + [honey.sql.helpers :as sql.helpers] [java-time :as t] [medley.core :as m] - [metabase-enterprise.audit-app.query-processor.middleware.handle-audit-queries :as qp.middleware.audit] + [metabase-enterprise.audit-app.query-processor.middleware.handle-audit-queries + :as qp.middleware.audit] [metabase.db :as mdb] [metabase.db.connection :as mdb.connection] [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] @@ -18,11 +18,11 @@ [metabase.query-processor.context :as qp.context] [metabase.query-processor.timezone :as qp.timezone] [metabase.util :as u] + [metabase.util.honey-sql-2-extensions :as h2x] [metabase.util.honeysql-extensions :as hx] [metabase.util.i18n :refer [tru]] [metabase.util.urls :as urls] - [schema.core :as s] - [toucan.db :as db])) + [schema.core :as s])) (def ^:private ^:const default-limit Integer/MAX_VALUE) @@ -32,9 +32,9 @@ honeysql-query (-> honeysql-query (update :limit (fn [query-limit] - (or limit query-limit default-limit))) + [:inline (or limit query-limit default-limit)])) (update :offset (fn [query-offset] - (or offset query-offset 0))))))) + [:inline (or offset query-offset 0)])))))) (defn- inject-cte-body-into-from [from ctes] @@ -99,7 +99,7 @@ (let [honeysql-query (cond-> honeysql-query ;; MySQL 5.x does not support CTEs, so convert them to subselects instead (= driver :mysql) CTEs->subselects)] - (db/honeysql->sql (add-default-params honeysql-query))) + (sql/format (add-default-params honeysql-query))) (catch Throwable e (throw (ex-info (tru "Error compiling audit query: {0}" (ex-message e)) {:driver driver, :honeysql-query honeysql-query} @@ -169,16 +169,16 @@ (user-full-name :u) ;; -> 'Cam Saul'" [user-table] - (let [first-name (hsql/qualify user-table :first_name) - last-name (hsql/qualify user-table :last_name) - email (hsql/qualify user-table :email)] - (hsql/call :case - [:and [:= nil first-name] [:= nil last-name]] - email - [:or [:= nil first-name] [:= nil last-name]] - (hx/concat (hsql/call :coalesce first-name "") (hsql/call :coalesce last-name "")) - :else - (hx/concat (hsql/call :coalesce first-name "") (hx/literal " ") (hsql/call :coalesce last-name ""))))) + (let [first-name (keyword (name user-table) "first_name") + last-name (keyword (name user-table) "last_name") + email (keyword (name user-table) "email")] + [:case + [:and [:= nil first-name] [:= nil last-name]] + email + [:or [:= nil first-name] [:= nil last-name]] + (h2x/concat [:coalesce first-name ""] [:coalesce last-name ""]) + :else + (h2x/concat [:coalesce first-name ""] (h2x/literal " ") [:coalesce last-name ""])])) (def datetime-unit-str->base-type "Map of datetime unit strings (possible params for queries that accept a datetime `unit` param) to the `:base_type` we @@ -211,80 +211,92 @@ (grouped-datetime :day :timestamp) ;; -> `cast(timestamp AS date)` [honeysql equivalent]" [unit expr] - (sql.qp/date (mdb/db-type) (keyword unit) expr)) + (binding [hx/*honey-sql-version* 2] + (sql.qp/date (mdb/db-type) (keyword unit) expr))) (defn first-non-null "Build a `CASE` statement that returns the first non-`NULL` of `exprs`." [& exprs] - (apply hsql/call :case (mapcat (fn [expr] - [[:not= expr nil] expr]) - exprs))) + (into [:case] + (mapcat (fn [expr] [[:not= expr nil] expr])) + exprs)) (defn zero-if-null "Build a `CASE` statement that will replace results of `expr` with `0` when it's `NULL`, perfect for things like counts." [expr] - (hsql/call :case [:not= expr nil] expr :else 0)) + [:case [:not= expr nil] expr :else 0]) (defn lowercase-field "Lowercase a SQL field, to enter into honeysql query" [field] - (hsql/call :lower field)) + [:lower field]) (defn add-45-days-clause "Add an appropriate `WHERE` clause to limit query to 45 days" [query date_column] - (hh/merge-where query [:> - (hx/cast :date date_column) - (hx/cast :date (hx/literal (t/format "yyyy-MM-dd" (t/minus (t/local-date) (t/days 45)))))])) + (sql.helpers/where query [:> + (h2x/cast :date date_column) + (h2x/cast :date (h2x/literal (t/format "yyyy-MM-dd" (t/minus (t/local-date) (t/days 45)))))])) (defn add-search-clause "Add an appropriate `WHERE` clause to `query` to see if any of the `fields-to-search` match `query-string`. (add-search-clause {} \"birds\" :t.name :db.name)" [query query-string & fields-to-search] - (hh/merge-where query (when (seq query-string) - (let [query-string (str \% (u/lower-case-en query-string) \%)] - (cons - :or - (for [field fields-to-search] - [:like (lowercase-field field) query-string])))))) + (sql.helpers/where query (when (seq query-string) + (let [query-string (str \% (u/lower-case-en query-string) \%)] + (cons + :or + (for [field fields-to-search] + [:like (lowercase-field field) query-string])))))) (defn add-sort-clause "Add an `ORDER BY` clause to `query` on `sort-column` and `sort-direction`. Most queries will just have explicit default `ORDER BY` clauses" [query sort-column sort-direction] - (hh/merge-order-by query [(keyword sort-column) (keyword sort-direction)])) + (sql.helpers/order-by query [(keyword sort-column) (keyword sort-direction)])) (defn card-public-url "Return HoneySQL for a `CASE` statement to return a Card's public URL if the `public_uuid` `field` is non-NULL." [field] - (hsql/call :case - [:not= field nil] - (hx/concat (urls/public-card-prefix) field))) + [:case + [:not= field nil] + (h2x/concat (urls/public-card-prefix) field)]) (defn native-or-gui "Return HoneySQL for a `CASE` statement to format the QueryExecution `:native` column as either `Native` or `GUI`." [query-execution-table] - (hsql/call :case [:= (hsql/qualify query-execution-table :native) true] (hx/literal "Native") :else (hx/literal "GUI"))) + [:case [:= (keyword (name query-execution-table) "native") true] (h2x/literal "Native") :else (h2x/literal "GUI")]) (defn card-name-or-ad-hoc "HoneySQL for a `CASE` statement to return the name of a Card, or `Ad-hoc` if Card name is `NULL`." [card-table] - (first-non-null (hsql/qualify card-table :name) (hx/literal "Ad-hoc"))) + (first-non-null (keyword (name card-table) "name") (h2x/literal "Ad-hoc"))) (defn query-execution-is-download "HoneySQL for a `WHERE` clause to restrict QueryExecution rows to downloads (i.e. executions returned in CSV/JSON/XLS format)." [query-execution-table] - [:in (hsql/qualify query-execution-table :context) #{"csv-download" "xlsx-download" "json-download"}]) + [:in (keyword (name query-execution-table) "context") #{"csv-download" "xlsx-download" "json-download"}]) + +(defn- format-separator + [_separator [x y]] + (let [[x-sql & x-args] (sql/format-expr x) + [y-sql & y-args] (sql/format-expr y)] + (into [(format "%s SEPARATOR %s" x-sql y-sql)] + cat + [x-args + y-args]))) + +(sql/register-fn! + ::separator + format-separator) (defn group-concat "Portable MySQL `group_concat`/Postgres `string_agg`" [expr separator] (if (= (mdb/db-type) :mysql) - (hsql/call :group_concat (hsql/raw (format "%s SEPARATOR %s" - (hformat/to-sql expr) - (hformat/to-sql (hx/literal separator))))) - (hsql/call :string_agg expr (hx/literal separator)))) + [:group_concat [::separator expr (h2x/literal separator)]] + [:string_agg expr (h2x/literal separator)])) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/card_and_dashboard_detail.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/card_and_dashboard_detail.clj index 071f64cb77c..150f89add40 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/card_and_dashboard_detail.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/card_and_dashboard_detail.clj @@ -1,13 +1,11 @@ (ns metabase-enterprise.audit-app.pages.common.card-and-dashboard-detail "Common queries used by both Card (Question) and Dashboard detail pages." (:require - [honeysql.core :as hsql] [metabase-enterprise.audit-app.pages.common :as common] [metabase.models.card :refer [Card]] [metabase.models.dashboard :refer [Dashboard]] - [metabase.models.interface :as mi] [metabase.models.revision :as revision] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [metabase.util.schema :as su] [schema.core :as s])) @@ -31,7 +29,7 @@ [:%count.* :views]] :from [:view_log] :where [:and - [:= :model (hx/literal model)] + [:= :model (h2x/literal model)] [:= :model_id model-id]] :group-by [grouped-timestamp] :order-by [[grouped-timestamp :asc]]} @@ -51,8 +49,8 @@ (common/reducible-query (-> {:select [[grouped-timestamp :date] - [(hsql/call :sum (hsql/call :case [:= :cache_hit true] 1 :else 0)) :cached_views] - [(hsql/call :sum (hsql/call :case [:= :cache_hit false] 1 :else 0)) :uncached_views]] + [[:sum [:case [:= :cache_hit true] [:inline 1] :else [:inline 0]]] :cached_views] + [[:sum [:case [:= :cache_hit false] [:inline 1] :else [:inline 0]]] :uncached_views]] :from [:query_execution] :where [:and [:= :card_id card-id] @@ -70,7 +68,7 @@ :results (let [grouped-timestamp (common/grouped-datetime unit :started_at)] (common/reducible-query (-> {:select [[grouped-timestamp :date] - [:%avg.running_time :avg_runtime]] + [[:avg :running_time] :avg_runtime]] :from [:query_execution] :where [:= :card_id card-id] :group-by [grouped-timestamp] @@ -79,14 +77,14 @@ (s/defn revision-history "Get a revision history table for a Card or Dashboard." - [model-entity :- (s/cond-pre (mi/InstanceOf Card) (mi/InstanceOf Dashboard)) - model-id :- su/IntGreaterThanZero] + [model :- (s/enum Card Dashboard) + model-id :- su/IntGreaterThanZero] {:metadata [[:timestamp {:display_name "Edited on", :base_type :type/DateTime}] [:user_id {:display_name "User ID", :base_type :type/Integer, :remapped_to :user_name}] [:user_name {:display_name "Edited by", :base_type :type/Name, :remapped_from :user_id}] [:change_made {:display_name "Change made", :base_type :type/Text}] [:revision_id {:display_name "Revision ID", :base_type :type/Integer}]] - :results (for [revision (revision/revisions+details model-entity model-id)] + :results (for [revision (revision/revisions+details model model-id)] {:timestamp (-> revision :timestamp) :user_id (-> revision :user :id) :user_name (-> revision :user :common_name) @@ -108,8 +106,8 @@ :from [[:view_log :vl]] :join [[:core_user :u] [:= :vl.user_id :u.id]] :where [:and - [:= :model (hx/literal model)] + [:= :model (h2x/literal model)] [:= :model_id model-id]] :order-by [[:vl.timestamp :desc] - [:%lower.u.last_name :asc] - [:%lower.u.first_name :asc]]})}) + [[:lower :u.last_name] :asc] + [[:lower :u.first_name] :asc]]})}) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/cards.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/cards.clj index cc9346bd4ae..a003b11ad70 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/cards.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/cards.clj @@ -2,7 +2,7 @@ (:require [metabase-enterprise.audit-app.pages.common :as common] [metabase.db.connection :as mdb.connection] - [metabase.util.honeysql-extensions :as hx])) + [metabase.util.honey-sql-2-extensions :as h2x])) (def avg-exec-time "HoneySQL for a CTE to include the average execution time for each Card." @@ -59,9 +59,11 @@ (def dashboards-ids "HoneySQL for a CTE to enumerate the dashboards for a Card. We get the actual ID's" - [:dash_card {:select [:card_id [(common/group-concat (hx/cast - (if (= (mdb.connection/db-type) :mysql) :char :text) - :report_dashboard.name) "|") :name_str]] + [:dash_card {:select [:card_id [(common/group-concat (h2x/cast + (if (= (mdb.connection/db-type) :mysql) :char :text) + :report_dashboard.name) + "|") + :name_str]] :from [:report_dashboardcard] :join [:report_dashboard [:= :report_dashboardcard.dashboard_id :report_dashboard.id]] :group-by [:card_id]}]) @@ -71,5 +73,5 @@ [:card_views {:select [[:model_id :card_id] [:%count.* :count]] :from [:view_log] - :where [:= :model (hx/literal "card")] + :where [:= :model (h2x/literal "card")] :group-by [:model_id]}]) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/dashboards.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/dashboards.clj index 2bb02c78a15..07be0e6e57f 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/dashboards.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/dashboards.clj @@ -1,9 +1,9 @@ (ns metabase-enterprise.audit-app.pages.common.dashboards - (:require [honeysql.core :as hsql] - [honeysql.helpers :as hh] - [metabase-enterprise.audit-app.pages.common :as common] - [metabase.util.honeysql-extensions :as hx] - [metabase.util.urls :as urls])) + (:require + [honey.sql.helpers :as sql.helpers] + [metabase-enterprise.audit-app.pages.common :as common] + [metabase.util.honey-sql-2-extensions :as h2x] + [metabase.util.urls :as urls])) (defn table "Dashboard table!" @@ -20,46 +20,46 @@ [:average_execution_time_ms {:display_name "Avg. exec. time (ms)", :base_type :type/Decimal}] [:total_views {:display_name "Total views", :base_type :type/Integer}]] :results (common/reducible-query - (-> - {:with [[:card_count {:select [:dashboard_id - [:%count.* :card_count]] - :from [:report_dashboardcard] - :group-by [:dashboard_id]}] - [:card_avg_execution_time {:select [:card_id - [:%avg.running_time :avg_running_time]] - :from [:query_execution] - :where [:not= :card_id nil] - :group-by [:card_id]}] - [:avg_execution_time {:select [:dc.dashboard_id - [:%avg.cxt.avg_running_time :avg_running_time]] - :from [[:report_dashboardcard :dc]] - :left-join [[:card_avg_execution_time :cxt] [:= :dc.card_id :cxt.card_id]] - :group-by [:dc.dashboard_id]}] - [:views {:select [[:model_id :dashboard_id] - [:%count.* :view_count]] - :from [:view_log] - :where [:= :model (hx/literal "dashboard")] - :group-by [:model_id]}]] - :select [[:d.id :dashboard_id] - [:d.name :title] - [:u.id :saved_by_id] - [(common/user-full-name :u) :saved_by] - [:d.created_at :saved_on] - [:d.cache_ttl :saved_on] - [:d.updated_at :last_edited_on] - [:cc.card_count :cards] - [(hsql/call :case - [:not= :d.public_uuid nil] - (hx/concat (urls/public-dashboard-prefix) :d.public_uuid)) - :public_link] - [:axt.avg_running_time :average_execution_time_ms] - [:v.view_count :total_views]] - :from [[:report_dashboard :d]] - :left-join [[:core_user :u] [:= :d.creator_id :u.id] - [:card_count :cc] [:= :d.id :cc.dashboard_id] - [:avg_execution_time :axt] [:= :d.id :axt.dashboard_id] - [:views :v] [:= :d.id :v.dashboard_id]] - :order-by [[:%lower.d.name :asc] - [:dashboard_id :asc]]} - (common/add-search-clause query-string :d.name) - (hh/merge-where where-clause)))}) + (-> + {:with [[:card_count {:select [:dashboard_id + [:%count.* :card_count]] + :from [:report_dashboardcard] + :group-by [:dashboard_id]}] + [:card_avg_execution_time {:select [:card_id + [:%avg.running_time :avg_running_time]] + :from [:query_execution] + :where [:not= :card_id nil] + :group-by [:card_id]}] + [:avg_execution_time {:select [:dc.dashboard_id + [[:avg :cxt.avg_running_time] :avg_running_time]] + :from [[:report_dashboardcard :dc]] + :left-join [[:card_avg_execution_time :cxt] [:= :dc.card_id :cxt.card_id]] + :group-by [:dc.dashboard_id]}] + [:views {:select [[:model_id :dashboard_id] + [:%count.* :view_count]] + :from [:view_log] + :where [:= :model (h2x/literal "dashboard")] + :group-by [:model_id]}]] + :select [[:d.id :dashboard_id] + [:d.name :title] + [:u.id :saved_by_id] + [(common/user-full-name :u) :saved_by] + [:d.created_at :saved_on] + [:d.cache_ttl :saved_on] + [:d.updated_at :last_edited_on] + [:cc.card_count :cards] + [[:case + [:not= :d.public_uuid nil] + (h2x/concat (urls/public-dashboard-prefix) :d.public_uuid)] + :public_link] + [:axt.avg_running_time :average_execution_time_ms] + [:v.view_count :total_views]] + :from [[:report_dashboard :d]] + :left-join [[:core_user :u] [:= :d.creator_id :u.id] + [:card_count :cc] [:= :d.id :cc.dashboard_id] + [:avg_execution_time :axt] [:= :d.id :axt.dashboard_id] + [:views :v] [:= :d.id :v.dashboard_id]] + :order-by [[[:lower :d.name] :asc] + [:dashboard_id :asc]]} + (common/add-search-clause query-string :d.name) + (sql.helpers/where where-clause)))}) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/pulses.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/pulses.clj index 1a268fb3cbe..3d5a62c1ce3 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/pulses.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/common/pulses.clj @@ -6,7 +6,7 @@ [clojure.tools.logging :as log] [metabase.models.collection :as collection] [metabase.util.cron :as u.cron] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [metabase.util.i18n :refer [trs tru]])) (def table-metadata @@ -64,7 +64,7 @@ :channel.schedule_day :channel.schedule_frame [:creator.id :creator_id] - [(hx/concat :creator.first_name (hx/literal " ") :creator.last_name) :creator_name] + [(h2x/concat :creator.first_name (h2x/literal " ") :creator.last_name) :creator_name] [:channel.created_at :created_at] [:pulse.parameters :pulse_parameters]] :from [[:pulse_channel :channel]] diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_detail.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_detail.clj index 8fb58047290..bbd7afa7e79 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_detail.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_detail.clj @@ -67,4 +67,4 @@ [:metabase_table :t] [:= :card.table_id :t.id] [:collection :coll] [:= :card.collection_id :coll.id] :card_views [:= :card.id :card_views.card_id]] - :order-by [[:%lower.card.name :asc]]})}) + :order-by [[[:lower :card.name] :asc]]})}) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_subscriptions.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_subscriptions.clj index 8aee1237230..7213e3ac053 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_subscriptions.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboard_subscriptions.clj @@ -30,8 +30,8 @@ (filter some?) [[:not= :pulse.dashboard_id nil] (when-not (str/blank? dashboard-name) - [:like :%lower.dashboard.name (str \% (u/lower-case-en dashboard-name) \%)])]))) - (assoc :order-by [[:%lower.dashboard.name :asc] + [:like [:lower :dashboard.name] (str \% (u/lower-case-en dashboard-name) \%)])]))) + (assoc :order-by [[[:lower :dashboard.name] :asc] ;; Newest first. ID instead of `created_at` because the column is currently only ;; second-resolution for MySQL which busts our tests [:channel.id :desc]]))) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboards.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboards.clj index 412c9d11613..309a76bb873 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboards.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/dashboards.clj @@ -4,7 +4,7 @@ [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] [metabase-enterprise.audit-app.pages.common.dashboards :as dashboards] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [schema.core :as s])) ;; Two-series timeseries that includes total number of Dashboard views and saves broken out by a `datetime-unit`. @@ -19,7 +19,7 @@ {:select [[(common/grouped-datetime datetime-unit :timestamp) :date] [:%count.* :views]] :from [:view_log] - :where [:= :model (hx/literal "dashboard")] + :where [:= :model (h2x/literal "dashboard")] :group-by [(common/grouped-datetime datetime-unit :timestamp)]}) date->views (zipmap (map :date views) (map :views views)) saves (common/query @@ -47,7 +47,7 @@ [:%count.* :views]] :from [[:view_log :vl]] :left-join [[:report_dashboard :d] [:= :vl.model_id :d.id]] - :where [:= :vl.model (hx/literal "dashboard")] + :where [:= :vl.model (h2x/literal "dashboard")] :group-by [:d.id] :order-by [[:%count.* :desc]] :limit 10})}) @@ -65,17 +65,17 @@ [:%count.* :views]] :from [[:view_log :vl]] :left-join [[:report_dashboard :d] [:= :vl.model_id :d.id]] - :where [:= :vl.model (hx/literal "dashboard")] + :where [:= :vl.model (h2x/literal "dashboard")] :group-by [:d.id] :order-by [[:%count.* :desc]] :limit 10}] [:card_running_time {:select [:qe.card_id - [:%avg.qe.running_time :avg_running_time]] + [[:avg :qe.running_time] :avg_running_time]] :from [[:query_execution :qe]] :where [:not= :qe.card_id nil] :group-by [:qe.card_id]}] [:dash_avg_running_time {:select [[:d.id :dashboard_id] - [:%avg.rt.avg_running_time :avg_running_time]] + [[:avg :rt.avg_running_time] :avg_running_time]] :from [[:report_dashboardcard :dc]] :left-join [[:card_running_time :rt] [:= :dc.card_id :rt.card_id] [:report_dashboard :d] [:= :dc.dashboard_id :d.id]] @@ -99,13 +99,13 @@ [:avg_running_time {:display_name "Avg. Question Load Time (ms)", :base_type :type/Decimal}]] :results (common/reducible-query {:with [[:card_running_time {:select [:qe.card_id - [:%avg.qe.running_time :avg_running_time]] + [[:avg :qe.running_time] :avg_running_time]] :from [[:query_execution :qe]] :where [:not= :qe.card_id nil] :group-by [:qe.card_id]}]] :select [[:d.id :dashboard_id] [:d.name :dashboard_name] - [:%avg.rt.avg_running_time :avg_running_time]] + [[:avg :rt.avg_running_time] :avg_running_time]] :from [[:report_dashboardcard :dc]] :left-join [[:card_running_time :rt] [:= :dc.card_id :rt.card_id] [:report_dashboard :d] [:= :dc.dashboard_id :d.id]] diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/databases.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/databases.clj index a737b515c00..c30ca42171d 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/databases.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/databases.clj @@ -1,9 +1,9 @@ (ns metabase-enterprise.audit-app.pages.databases (:require - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] [metabase.util.cron :as u.cron] + [metabase.util.honey-sql-2-extensions :as h2x] [schema.core :as s])) ;; SELECT @@ -30,13 +30,13 @@ {:select [[:db.id :database_id] [:db.name :database_name] [:%count.* :queries] - [:%avg.qe.running_time :avg_running_time]] + [[:avg :qe.running_time] :avg_running_time]] :from [[:query_execution :qe]] :join [[:report_card :card] [:= :qe.card_id :card.id] [:metabase_table :t] [:= :card.table_id :t.id] [:metabase_database :db] [:= :t.db_id :db.id]] :group-by [:db.id] - :order-by [[:%lower.db.name :asc]]})}) + :order-by [[[:lower :db.name] :asc]]})}) ;; Query that returns count of query executions grouped by Database and a `datetime-unit`. (s/defmethod audit.i/internal-query ::query-executions-by-time @@ -64,7 +64,7 @@ :from [:qx] :left-join [[:metabase_database :db] [:= :qx.database_id :db.id]] :order-by [[:qx.date :asc] - [:%lower.db.name :asc] + [[:lower :db.name] :asc] [:qx.database_id :asc]]})}) ;; DEPRECATED Use `::query-executions-by-time` instead. Query that returns count of query executions grouped by @@ -90,7 +90,7 @@ :results (common/reducible-query (-> {:with [[:counts {:select [[:db_id :id] - [(hsql/call :distinct-count :schema) :schemas] + [[::h2x/distinct-count :schema] :schemas] [:%count.* :tables]] :from [:metabase_table] :group-by [:db_id]}]] @@ -103,7 +103,7 @@ [:db.cache_ttl :cache_ttl]] :from [[:metabase_database :db]] :left-join [:counts [:= :db.id :counts.id]] - :order-by [[:%lower.db.name :asc] + :order-by [[[:lower :db.name] :asc] [:database_id :asc]]} (common/add-search-clause query-string :db.name))) :xform (map #(update (vec %) 3 u.cron/describe-cron-string))})) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/downloads.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/downloads.clj index 14dc2b320bd..e4693e93997 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/downloads.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/downloads.clj @@ -2,11 +2,11 @@ "Audit queries returning info about query downloads. Query downloads are any query executions whose results are returned as CSV/JSON/XLS." (:require - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] [metabase.db :as mdb] [metabase.driver.sql.query-processor :as sql.qp] + [metabase.util.honey-sql-2-extensions :as h2x] [metabase.util.honeysql-extensions :as hx])) ;; Pairs of count of rows downloaded and date downloaded for the 1000 largest (in terms of row count) queries over the @@ -25,7 +25,8 @@ :from [[:query_execution :qe]] :left-join [[:core_user :u] [:= :qe.executor_id :u.id]] :where [:and - [:> :qe.started_at (sql.qp/add-interval-honeysql-form (mdb/db-type) :%now -30 :day)] + [:> :qe.started_at (binding [hx/*honey-sql-version* 2] + (sql.qp/add-interval-honeysql-form (mdb/db-type) :%now -30 :day))] (common/query-execution-is-download :qe)] :order-by [[:qe.result_rows :desc]] :limit 1000})}) @@ -68,11 +69,11 @@ "`CASE` expression to put `result_rows` in appropriate buckets. Looks something like: CASE ... result_rows <= 100 THEN 100 ..." - (apply hsql/call :case (concat - (mapcat (fn [bucket-max] - [[:<= :result_rows bucket-max] bucket-max]) - bucket-maxes) - [:else -1]))) + (into [:case] (concat + (mapcat (fn [bucket-max] + [[:<= :result_rows bucket-max] bucket-max]) + bucket-maxes) + [:else -1]))) (def ^:private bucket-ranges "Pairs like [[0 10], [11 100], ...]" @@ -91,18 +92,18 @@ (defn- bucket-range->literal "Given a bucket range pair like [101 1000] return a formatted string including commas like `101-1,000`." [[bucket-min bucket-max]] - (hx/literal (format "%s-%s" (format-number-add-commas bucket-min) (format-number-add-commas bucket-max)))) + (h2x/literal (format "%s-%s" (format-number-add-commas bucket-min) (format-number-add-commas bucket-max)))) (def ^:private bucket->range-str-case-expression "`CASE` expression to generate range strings for each bucket. Looks something like: CASE ... (rows_bucket_max = 1000) THEN '101-1,000' ..." - (apply hsql/call :case (concat - (mapcat (fn [[_ bucket-max :as bucket-range]] - [[:= :rows_bucket_max bucket-max] (bucket-range->literal bucket-range)]) - bucket-ranges) - [[:= :rows_bucket_max -1] - (hx/literal (format "> %s" (format-number-add-commas (last bucket-maxes))))]))) + (into [:case] (concat + (mapcat (fn [[_ bucket-max :as bucket-range]] + [[:= :rows_bucket_max bucket-max] (bucket-range->literal bucket-range)]) + bucket-ranges) + [[:= :rows_bucket_max -1] + (h2x/literal (format "> %s" (format-number-add-commas (last bucket-maxes))))]))) ;; Query download count broken out by bucketed number of rows of query. E.g. 10 downloads of queries with 0-10 rows, ;; 15 downloads of queries with 11-100, etc. Intended to power bar chart. diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/queries.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/queries.clj index 1f854b04f76..48699a60963 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/queries.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/queries.clj @@ -1,11 +1,10 @@ (ns metabase-enterprise.audit-app.pages.queries (:require - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] [metabase-enterprise.audit-app.pages.common.cards :as cards] [metabase.db.connection :as mdb.connection] - [metabase.util.honeysql-extensions :as hx])) + [metabase.util.honey-sql-2-extensions :as h2x])) ;; DEPRECATED Query that returns data for a two-series timeseries chart with number of queries ran and average query ;; running time broken out by day. @@ -15,12 +14,12 @@ [:views {:display_name "Views", :base_type :type/Integer}] [:avg_running_time {:display_name "Avg. Running Time (ms)", :base_type :type/Decimal}]] :results (common/reducible-query - {:select [[(hx/cast :date :started_at) :day] + {:select [[(h2x/cast :date :started_at) :day] [:%count.* :views] - [:%avg.running_time :avg_running_time]] + [[:avg :running_time] :avg_running_time]] :from [:query_execution] - :group-by [(hx/cast :date :started_at)] - :order-by [[(hx/cast :date :started_at) :asc]]})}) + :group-by [(h2x/cast :date :started_at)] + :order-by [[(h2x/cast :date :started_at) :asc]]})}) ;; Query that returns the 10 most-popular Cards based on number of query executions, in descending order. (defmethod audit.i/internal-query ::most-popular @@ -48,7 +47,7 @@ :results (common/reducible-query {:select [[:c.id :card_id] [:c.name :card_name] - [:%avg.running_time :avg_running_time]] + [[:avg :running_time] :avg_running_time]] :from [[:query_execution :qe]] :join [[:report_card :c] [:= :qe.card_id :c.id]] :group-by [:c.id] @@ -83,50 +82,51 @@ [:user_name {:display_name "Created By", :base_type :type/Text :remapped_from :user_id}] [:updated_at {:display_name "Updated At", :base_type :type/DateTime}]] :results (common/reducible-query - (let [coll-name (hsql/call :coalesce :coll.name "Our Analytics") - error-substr (hsql/call :concat - (hsql/call :substring :latest_qe.error - (if (= (mdb.connection/db-type) :mysql) 1 0) - 60) - "...") - dash-count (hsql/call :coalesce :dash_card.count 0)] - (-> - {:with [cards/query-runs - cards/latest-qe - cards/dashboards-count] - :select [[:card.id :card_id] - [:card.name :card_name] - [error-substr :error_substr] - :collection_id - [coll-name :collection_name] - :card.database_id - [:db.name :database_name] - [:t.schema :schema_name] - :card.table_id - [:t.name :table_name] - [:latest_qe.started_at :last_run_at] - [:query_runs.count :total_runs] - [dash-count :num_dashboards] - [:card.creator_id :user_id] - [(common/user-full-name :u) :user_name] - [:card.updated_at :updated_at]] - :from [[:report_card :card]] - :left-join [[:collection :coll] [:= :card.collection_id :coll.id] - [:metabase_database :db] [:= :card.database_id :db.id] - [:metabase_table :t] [:= :card.table_id :t.id] - [:core_user :u] [:= :card.creator_id :u.id] - :latest_qe [:= :card.id :latest_qe.card_id] - :query_runs [:= :card.id :query_runs.card_id] - :dash_card [:= :card.id :dash_card.card_id]] - :where [:and - [:= :card.archived false] - [:<> :latest_qe.error nil]]} - (common/add-search-clause error-filter :latest_qe.error) - (common/add-search-clause db-filter :db.name) - (common/add-search-clause collection-filter coll-name) - (common/add-sort-clause - (or sort-column "card.name") - (or sort-direction "asc")))))})) + (let [coll-name [:coalesce :coll.name "Our Analytics"] + error-substr [:concat + [:substring + :latest_qe.error + [:inline (if (= (mdb.connection/db-type) :mysql) 1 0)] + [:inline 60]] + "..."] + dash-count [:coalesce :dash_card.count [:inline 0]]] + (-> + {:with [cards/query-runs + cards/latest-qe + cards/dashboards-count] + :select [[:card.id :card_id] + [:card.name :card_name] + [error-substr :error_substr] + :collection_id + [coll-name :collection_name] + :card.database_id + [:db.name :database_name] + [:t.schema :schema_name] + :card.table_id + [:t.name :table_name] + [:latest_qe.started_at :last_run_at] + [:query_runs.count :total_runs] + [dash-count :num_dashboards] + [:card.creator_id :user_id] + [(common/user-full-name :u) :user_name] + [:card.updated_at :updated_at]] + :from [[:report_card :card]] + :left-join [[:collection :coll] [:= :card.collection_id :coll.id] + [:metabase_database :db] [:= :card.database_id :db.id] + [:metabase_table :t] [:= :card.table_id :t.id] + [:core_user :u] [:= :card.creator_id :u.id] + :latest_qe [:= :card.id :latest_qe.card_id] + :query_runs [:= :card.id :query_runs.card_id] + :dash_card [:= :card.id :dash_card.card_id]] + :where [:and + [:= :card.archived false] + [:<> :latest_qe.error nil]]} + (common/add-search-clause error-filter :latest_qe.error) + (common/add-search-clause db-filter :db.name) + (common/add-search-clause collection-filter coll-name) + (common/add-sort-clause + (or sort-column "card.name") + (or sort-direction "asc")))))})) ;; A list of all questions. ;; diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/query_detail.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/query_detail.clj index d21419466fa..5933d71f867 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/query_detail.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/query_detail.clj @@ -2,7 +2,6 @@ "Queries to show details about a (presumably ad-hoc) query." (:require [cheshire.core :as json] - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] [metabase-enterprise.audit-app.pages.common.cards :as cards] @@ -37,7 +36,7 @@ [:card.name :card_name] [:latest_qe.error :error_str] :collection_id - [(hsql/call :coalesce :coll.name "Our Analytics") :collection_name] + [[:coalesce :coll.name "Our Analytics"] :collection_name] :card.database_id [:db.name :database_name] [:t.schema :schema_name] diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/schemas.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/schemas.clj index c61722047a7..f03e6dee477 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/schemas.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/schemas.clj @@ -2,7 +2,7 @@ (:require [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [schema.core :as s])) ;; WITH counts AS ( @@ -41,7 +41,7 @@ [:not= :qe.card_id nil] [:not= :card.database_id nil] [:not= :card.table_id nil]]}]] - :select [[(hx/concat :db_name (hx/literal " ") :db_schema) :schema] + :select [[(h2x/concat :db_name (h2x/literal " ") :db_schema) :schema] [:%count.* :executions]] :from [:counts] :group-by [:db_name :db_schema] @@ -85,8 +85,8 @@ [:not= :qe.card_id nil] [:not= :card.database_id nil] [:not= :card.table_id nil]]}]] - :select [[(hx/concat :db_name (hx/literal " ") :db_schema) :schema] - [:%avg.running_time :avg_running_time]] + :select [[(h2x/concat :db_name (h2x/literal " ") :db_schema) :schema] + [[:avg :running_time] :avg_running_time]] :from [:counts] :group-by [:db_name :db_schema] :order-by [[:avg_running_time :desc]] @@ -147,7 +147,7 @@ :order-by [[:db.id :asc] [:t.schema :asc]]}]] :select [:s.database_id [:s.database_name :database] - [(hx/concat :s.database_id (hx/literal ".") :s.schema) :schema_id] + [(h2x/concat :s.database_id (h2x/literal ".") :s.schema) :schema_id] :s.schema :s.tables [:c.saved_count :saved_queries]] diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/tables.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/tables.clj index 27744a988a8..16841c7f1c6 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/tables.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/tables.clj @@ -2,7 +2,7 @@ (:require [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [schema.core :as s])) ;; WITH table_executions AS ( @@ -34,7 +34,7 @@ :order-by [[:%count.* asc-or-desc]] :limit 10}]] :select [:tx.table_id - [(hx/concat :db.name (hx/literal " ") :t.schema (hx/literal " ") :t.name) :table_name] + [(h2x/concat :db.name (h2x/literal " ") :t.schema (h2x/literal " ") :t.name) :table_name] :tx.executions] :from [[:table_executions :tx]] :join [[:metabase_table :t] [:= :tx.table_id :t.id] @@ -67,15 +67,15 @@ (-> {:select [[:db.id :database_id] [:db.name :database_name] - [(hx/concat :db.id (hx/literal ".") :t.schema) :schema_id] + [(h2x/concat :db.id (h2x/literal ".") :t.schema) :schema_id] [:t.schema :table_schema] [:t.id :table_id] [:t.name :table_name] [:t.display_name :table_display_name]] :from [[:metabase_table :t]] :join [[:metabase_database :db] [:= :t.db_id :db.id]] - :order-by [[:%lower.db.name :asc] - [:%lower.t.schema :asc] - [:%lower.t.name :asc]] + :order-by [[[:lower :db.name] :asc] + [[:lower :t.schema] :asc] + [[:lower :t.name] :asc]] :where [:= :t.active true]} (common/add-search-clause query-string :db.name :t.schema :t.name :t.display_name)))})) diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/user_detail.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/user_detail.clj index b67dbdba003..d1060ca1285 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/user_detail.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/user_detail.clj @@ -1,11 +1,10 @@ (ns metabase-enterprise.audit-app.pages.user-detail (:require - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] [metabase-enterprise.audit-app.pages.common.cards :as cards] [metabase-enterprise.audit-app.pages.common.dashboards :as dashboards] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [metabase.util.schema :as su] [metabase.util.urls :as urls] [ring.util.codec :as codec] @@ -44,19 +43,19 @@ :from [:pulse] :where [:= :creator_id user-id]}] [:users {:select [[(common/user-full-name :u) :name] - [(hsql/call :case - [:= :u.is_superuser true] - (hx/literal "Admin") - :else - (hx/literal "User")) + [[:case + [:= :u.is_superuser true] + (h2x/literal "Admin") + :else + (h2x/literal "User")] :role] :id :date_joined - [(hsql/call :case - [:= nil :u.sso_source] - (hx/literal "Email") - :else - :u.sso_source) + [[:case + [:= nil :u.sso_source] + (h2x/literal "Email") + :else + :u.sso_source] :signup_method] :last_name] :from [[:core_user :u]] @@ -91,7 +90,7 @@ :left-join [[:report_dashboard :d] [:= :vl.model_id :d.id]] :where [:and [:= :vl.user_id user-id] - [:= :vl.model (hx/literal "dashboard")]] + [:= :vl.model (h2x/literal "dashboard")]] :group-by [:d.id] :order-by [[:%count.* :desc]] :limit 10})}) @@ -110,7 +109,7 @@ :left-join [[:report_card :d] [:= :vl.model_id :d.id]] :where [:and [:= :vl.user_id user-id] - [:= :vl.model (hx/literal "card")]] + [:= :vl.model (h2x/literal "card")]] :group-by [:d.id] :order-by [[:%count.* :desc]] :limit 10})}) @@ -171,7 +170,7 @@ [:coll.name :collection_name]] :from [[:view_log :vl]] :where [:and - [:= :vl.model (hx/literal "dashboard")] + [:= :vl.model (h2x/literal "dashboard")] [:= :vl.user_id user-id]] :join [[:report_dashboard :dash] [:= :vl.model_id :dash.id]] :left-join [[:collection :coll] [:= :dash.collection_id :coll.id]] @@ -232,9 +231,9 @@ [:t.name :table_name] :avg_exec_time.avg_running_time_ms :card.cache_ttl - [(hsql/call :case - [:not= :card.public_uuid nil] - (hx/concat (urls/public-card-prefix) :card.public_uuid)) + [[:case + [:not= :card.public_uuid nil] + (h2x/concat (urls/public-card-prefix) :card.public_uuid)] :public_link] [:card_views.count :total_views]] :from [[:report_card :card]] @@ -244,7 +243,7 @@ [:collection :coll] [:= :card.collection_id :coll.id] :card_views [:= :card.id :card_views.card_id]] :where [:= :card.creator_id user-id] - :order-by [[:%lower.card.name :asc]]})}) + :order-by [[[:lower :card.name] :asc]]})}) ;; Table of query downloads (i.e., queries whose results are returned as CSV/JSON/XLS) done by this user, ordered by ;; most recent. diff --git a/enterprise/backend/src/metabase_enterprise/audit_app/pages/users.clj b/enterprise/backend/src/metabase_enterprise/audit_app/pages/users.clj index 3b312aca514..6ec6728bfe0 100644 --- a/enterprise/backend/src/metabase_enterprise/audit_app/pages/users.clj +++ b/enterprise/backend/src/metabase_enterprise/audit_app/pages/users.clj @@ -1,9 +1,8 @@ (ns metabase-enterprise.audit-app.pages.users (:require - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] - [metabase.util.honeysql-extensions :as hx] + [metabase.util.honey-sql-2-extensions :as h2x] [ring.util.codec :as codec] [schema.core :as s])) @@ -18,7 +17,7 @@ :results (common/reducible-query {:with [[:user_qe {:select [:executor_id [:%count.* :executions] - [(hx/cast :date :started_at) :day]] + [(h2x/cast :date :started_at) :day]] :from [:query_execution] :group-by [:executor_id :day]}]] :select [[:%count.* :users] @@ -39,7 +38,7 @@ ;; them(!) :results (let [active (common/query {:select [[(common/grouped-datetime datetime-unit :started_at) :date] - [:%distinct-count.executor_id :count]] + [[::h2x/distinct-count :executor_id] :count]] :from [:query_execution] :group-by [(common/grouped-datetime datetime-unit :started_at)]}) date->active (zipmap (map :date active) (map :count active)) @@ -76,9 +75,9 @@ :from [[:core_user :u]] :left-join [:qe_count [:= :qe_count.executor_id :u.id]] :order-by [[:count :desc] - [:%lower.u.last_name :asc] - [:%lower.u.first_name :asc] - [:%lower.u.email :asc]] + [[:lower :u.last_name] :asc] + [[:lower :u.first_name] :asc] + [[:lower :u.email] :asc]] :limit 10})}) ;; Query that returns the 10 Users with the most saved objects in descending order. @@ -102,7 +101,7 @@ :group-by [:creator_id]}]] :select [[:u.id :user_id] [(common/user-full-name :u) :user_name] - [(hx/+ (common/zero-if-null :card_saves.count) + [(h2x/+ (common/zero-if-null :card_saves.count) (common/zero-if-null :dashboard_saves.count) (common/zero-if-null :pulse_saves.count)) :saves]] @@ -132,15 +131,15 @@ :limit 10}]] :select [[:u.id :user_id] [(common/user-full-name :u) :name] - [(hsql/call :case [:not= :exec_time.execution_time_ms nil] :exec_time.execution_time_ms - :else 0) + [[:case [:not= :exec_time.execution_time_ms nil] :exec_time.execution_time_ms + :else 0] :execution_time_ms]] :from [[:core_user :u]] :left-join [:exec_time [:= :exec_time.executor_id :u.id]] :order-by [[:execution_time_ms :desc] - [:%lower.u.last_name :asc] - [:%lower.u.first_name :asc] - [:%lower.u.email :asc]] + [[:lower :u.last_name] :asc] + [[:lower :u.first_name] :asc] + [[:lower :u.email] :asc]] :limit 10})}) ;; A table of all the Users for this instance, and various statistics about them (see metadata below). @@ -187,19 +186,19 @@ :left-join [[:core_user :u] [:= :u.id :p.creator_id]] :group-by [:u.id]}] [:users {:select [[(common/user-full-name :u) :name] - [(hsql/call :case - [:= :u.is_superuser true] - (hx/literal "Admin") - :else - (hx/literal "User")) + [[:case + [:= :u.is_superuser true] + (h2x/literal "Admin") + :else + (h2x/literal "User")] :role] :id :date_joined - [(hsql/call :case - [:= nil :u.sso_source] - (hx/literal "Email") - :else - :u.sso_source) + [[:case + [:= nil :u.sso_source] + (h2x/literal "Email") + :else + :u.sso_source] :signup_method] :last_name :first_name] @@ -220,8 +219,8 @@ :questions_saved [:= :u.id :questions_saved.id] :dashboards_saved [:= :u.id :dashboards_saved.id] :pulses_saved [:= :u.id :pulses_saved.id]] - :order-by [[:%lower.u.last_name :asc] - [:%lower.u.first_name :asc]]} + :order-by [[[:lower :u.last_name] :asc] + [[:lower :u.first_name] :asc]]} (common/add-search-clause query-string :u.first_name :u.last_name)))})) ;; Return a log of all query executions, including information about the Card associated with the query and the @@ -288,7 +287,7 @@ [:u.id :user_id] [(common/user-full-name :u) :user_name]] :from [[:view_log :vl]] - :where [:= :vl.model (hx/literal "dashboard")] + :where [:= :vl.model (h2x/literal "dashboard")] :join [[:report_dashboard :dash] [:= :vl.model_id :dash.id] [:core_user :u] [:= :vl.user_id :u.id]] :left-join [[:collection :coll] [:= :dash.collection_id :coll.id]] diff --git a/enterprise/backend/test/metabase_enterprise/audit_app/pages/common_test.clj b/enterprise/backend/test/metabase_enterprise/audit_app/pages/common_test.clj index 4b71d5e6c65..4849b5b088f 100644 --- a/enterprise/backend/test/metabase_enterprise/audit_app/pages/common_test.clj +++ b/enterprise/backend/test/metabase_enterprise/audit_app/pages/common_test.clj @@ -1,13 +1,14 @@ (ns metabase-enterprise.audit-app.pages.common-test (:require [clojure.test :refer :all] - [honeysql.core :as hsql] [metabase-enterprise.audit-app.interface :as audit.i] [metabase-enterprise.audit-app.pages.common :as common] - [metabase.public-settings.premium-features-test :as premium-features-test] + [metabase.public-settings.premium-features-test + :as premium-features-test] [metabase.query-processor :as qp] [metabase.test :as mt] [metabase.util :as u] + [metabase.util.honey-sql-2-extensions :as h2x] [metabase.util.honeysql-extensions :as hx])) (defn- run-query @@ -23,24 +24,28 @@ {:metadata [[:A {:display_name "A", :base_type :type/DateTime}] [:B {:display_name "B", :base_type :type/Integer}]] :results (common/query - {:union-all [{:select [[a1 :A] [2 :B]]} - {:select [[3 :A] [4 :B]]}]})}) + {:union-all [{:select [[[:inline a1] :A] + [[:inline 2] :B]]} + {:select [[[:inline 3] :A] + [[:inline 4] :B]]}]})}) (defmethod audit.i/internal-query ::reducible-format-query-fn [_ a1] {:metadata [[:A {:display_name "A", :base_type :type/DateTime}] [:B {:display_name "B", :base_type :type/Integer}]] :results (common/reducible-query - {:union-all [{:select [[a1 :A] [2 :B]]} - {:select [[3 :A] [4 :B]]}]}) + {:union-all [{:select [[[:inline a1] :A] + [[:inline 2] :B]]} + {:select [[[:inline 3] :A] + [[:inline 4] :B]]}]}) :xform (map #(update (vec %) 0 inc))}) (deftest transform-results-test (testing "Make sure query function result are transformed to QP results correctly" (premium-features-test/with-premium-features #{:audit-app} - (doseq [[format-name {:keys [query-type expected-rows]}] {"legacy" {:query-type ::legacy-format-query-fn + (doseq [[format-name {:keys [query-type expected-rows]}] {"legacy" {:query-type ::legacy-format-query-fn :expected-rows [[100 2] [3 4]]} - "reducible" {:query-type ::reducible-format-query-fn + "reducible" {:query-type ::reducible-format-query-fn :expected-rows [[101 2] [4 4]]}}] (testing (format "format = %s" format-name) (let [results (delay (run-query query-type :args [100]))] @@ -52,28 +57,29 @@ (is (= expected-rows (mt/rows @results)))))))))) -(deftest add-45-days-clause-test +(deftest ^:parallel add-45-days-clause-test (testing "add 45 days clause" - (is (= - {:where - [:> - (hx/with-type-info - (hsql/call :cast :bob.dobbs #honeysql.types.SqlRaw{:s "date"}) - {::hx/database-type "date"}) - nil]} - (assoc-in (#'common/add-45-days-clause {} :bob.dobbs) [:where 2] nil))))) + (is (= {:where + [:> + (h2x/with-type-info + [:cast :bob.dobbs [:raw "date"]] + {::hx/database-type "date"}) + nil]} + (assoc-in (#'common/add-45-days-clause {} :bob.dobbs) [:where 2] nil))))) -(deftest add-search-clause-test +(deftest ^:parallel add-search-clause-test (testing "add search clause" - (is (= {:where `(:or [:like ~(hsql/call :lower :t.name) "%birds%"] [:like ~(hsql/call :lower :db.name) "%birds%"])} + (is (= {:where [:or + [:like [:lower :t.name] "%birds%"] + [:like [:lower :db.name] "%birds%"]]} (#'common/add-search-clause {} "birds" :t.name :db.name))))) (deftest query-limit-and-offset-test (testing "Make sure params passed in as part of the query map are respected" (premium-features-test/with-premium-features #{:audit-app} - (doseq [[format-name {:keys [query-type expected-rows]}] {"legacy" {:query-type ::legacy-format-query-fn + (doseq [[format-name {:keys [query-type expected-rows]}] {"legacy" {:query-type ::legacy-format-query-fn :expected-rows [[100 2] [3 4]]} - "reducible" {:query-type ::reducible-format-query-fn + "reducible" {:query-type ::reducible-format-query-fn :expected-rows [[101 2] [4 4]]}}] (testing (format "format = %s" format-name) (testing :limit @@ -83,12 +89,12 @@ (is (= [(second expected-rows)] (mt/rows (run-query query-type :args [100], :offset 1)))))))))) -(deftest CTES->subselects-test +(deftest ^:parallel CTES->subselects-test (testing "FROM substitution" (is (= {:from [[{:from [[:view_log :vl]]} :mp]]} (#'common/CTEs->subselects - {:with [[:most_popular {:from [[:view_log :vl]]}]] - :from [[:most_popular :mp]]})))) + {:with [[:most_popular {:from [[:view_log :vl]]}]] + :from [[:most_popular :mp]]})))) (testing "JOIN substitution" (is (= {:left-join [[{:from [[:query_execution :qe]]} :qe_count] [:= :qe_count.executor_id :u.id]]} @@ -118,11 +124,11 @@ [:report_dashboard :d] [:= :dc.dashboard_id :d.id]] - :where [:in :d.id {:select [:dashboard_id] - :from [[{:select [[:d.id :dashboard_id]] - :from [[:view_log :vl]] - :left-join [[:report_dashboard :d] - [:= :vl.model_id :d.id]]} :most_popular]]}]} :rt] + :where [:in :d.id {:select [:dashboard_id] + :from [[{:select [[:d.id :dashboard_id]] + :from [[:view_log :vl]] + :left-join [[:report_dashboard :d] + [:= :vl.model_id :d.id]]} :most_popular]]}]} :rt] [:= :mp.dashboard_id :rt.dashboard_id]]} (#'common/CTEs->subselects {:with [[:most_popular {:select [[:d.id :dashboard_id]] diff --git a/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj b/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj index b3c31212f97..b3bc5bb1f66 100644 --- a/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj +++ b/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj @@ -79,38 +79,38 @@ (driver/with-driver (or driver/*driver* :h2) (assert (driver/supports? driver/*driver* :native-parameters)) {:query (mt/native-query - {:query - (format-honeysql - {:select [:*] - :from [(identifier :venues)] - :where [:= (identifier :venues :category_id) (hsql/raw "{{cat}}")] - :order-by [(identifier :venues :id)]}) - - :template_tags - {:cat {:name "cat" :display_name "cat" :type "number" :required true}}}) + {:query + (format-honeysql + {:select [:*] + :from [(identifier :venues)] + :where [:= (identifier :venues :category_id) (hx/raw "{{cat}}")] + :order-by [(identifier :venues :id)]}) + + :template_tags + {:cat {:name "cat" :display_name "cat" :type "number" :required true}}}) :remappings {:cat ["variable" ["template-tag" "cat"]]}})) (defn- parameterized-sql-with-join-gtap-def [] (driver/with-driver (or driver/*driver* :h2) (assert (driver/supports? driver/*driver* :native-parameters)) {:query (mt/native-query - {:query - (format-honeysql - {:select [(identifier :checkins :id) - (identifier :checkins :user_id) - (identifier :venues :name) - (identifier :venues :category_id)] - :from [(identifier :checkins)] - :left-join [(identifier :venues) - [:= (identifier :checkins :venue_id) (identifier :venues :id)]] - :where [:= (identifier :checkins :user_id) (hsql/raw "{{user}}")] - :order-by [[(identifier :checkins :id) :asc]]}) - - :template_tags - {"user" {:name "user" - :display-name "User ID" - :type :number - :required true}}}) + {:query + (format-honeysql + {:select [(identifier :checkins :id) + (identifier :checkins :user_id) + (identifier :venues :name) + (identifier :venues :category_id)] + :from [(identifier :checkins)] + :left-join [(identifier :venues) + [:= (identifier :checkins :venue_id) (identifier :venues :id)]] + :where [:= (identifier :checkins :user_id) (hx/raw "{{user}}")] + :order-by [[(identifier :checkins :id) :asc]]}) + + :template_tags + {"user" {:name "user" + :display-name "User ID" + :type :number + :required true}}}) :remappings {:user ["variable" ["template-tag" "user"]]}})) (defn- venue-names-native-gtap-def [] diff --git a/modules/drivers/athena/src/metabase/driver/athena.clj b/modules/drivers/athena/src/metabase/driver/athena.clj index 425fd1f57db..aec7203bb70 100644 --- a/modules/drivers/athena/src/metabase/driver/athena.clj +++ b/modules/drivers/athena/src/metabase/driver/athena.clj @@ -5,7 +5,6 @@ [clojure.set :as set] [clojure.string :as str] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [honeysql.format :as hformat] [java-time :as t] [medley.core :as m] @@ -203,7 +202,7 @@ :limit items ::offset (* items (dec page)))) -(defn- date-trunc [unit expr] (hsql/call :date_trunc (hx/literal unit) expr)) +(defn- date-trunc [unit expr] (hx/call :date_trunc (hx/literal unit) expr)) ;;; Example of handling report timezone ;;; (defn- date-trunc @@ -211,8 +210,8 @@ ;;; [unit expr] ;;; (let [timezone (get-in sql.qp/*query* [:settings :report-timezone])] ;;; (if (nil? timezone) -;;; (hsql/call :date_trunc (hx/literal unit) expr) -;;; (hsql/call :date_trunc (hx/literal unit) timezone expr)))) +;;; (hx/call :date_trunc (hx/literal unit) expr) +;;; (hx/call :date_trunc (hx/literal unit) timezone expr)))) (defmethod driver/db-start-of-week :athena [_driver] @@ -222,40 +221,40 @@ ;;; If `expr` is a date, we need to cast it to a timestamp before we can truncate to a finer granularity Ideally, we ;;; should make this conditional. There's a generic approach above, but different use cases should b tested. -(defmethod sql.qp/date [:athena :minute] [_driver _unit expr] (hsql/call :date_trunc (hx/literal :minute) expr)) -(defmethod sql.qp/date [:athena :hour] [_driver _unit expr] (hsql/call :date_trunc (hx/literal :hour) expr)) -(defmethod sql.qp/date [:athena :day] [_driver _unit expr] (hsql/call :date_trunc (hx/literal :day) expr)) -(defmethod sql.qp/date [:athena :month] [_driver _unit expr] (hsql/call :date_trunc (hx/literal :month) expr)) -(defmethod sql.qp/date [:athena :quarter] [_driver _unit expr] (hsql/call :date_trunc (hx/literal :quarter) expr)) -(defmethod sql.qp/date [:athena :year] [_driver _unit expr] (hsql/call :date_trunc (hx/literal :year) expr)) +(defmethod sql.qp/date [:athena :minute] [_driver _unit expr] (hx/call :date_trunc (hx/literal :minute) expr)) +(defmethod sql.qp/date [:athena :hour] [_driver _unit expr] (hx/call :date_trunc (hx/literal :hour) expr)) +(defmethod sql.qp/date [:athena :day] [_driver _unit expr] (hx/call :date_trunc (hx/literal :day) expr)) +(defmethod sql.qp/date [:athena :month] [_driver _unit expr] (hx/call :date_trunc (hx/literal :month) expr)) +(defmethod sql.qp/date [:athena :quarter] [_driver _unit expr] (hx/call :date_trunc (hx/literal :quarter) expr)) +(defmethod sql.qp/date [:athena :year] [_driver _unit expr] (hx/call :date_trunc (hx/literal :year) expr)) (defmethod sql.qp/date [:athena :week] [driver _ expr] - (sql.qp/adjust-start-of-week driver (partial hsql/call :date_trunc (hx/literal :week)) expr)) + (sql.qp/adjust-start-of-week driver (partial hx/call :date_trunc (hx/literal :week)) expr)) ;;;; Datetime extraction functions -(defmethod sql.qp/date [:athena :minute-of-hour] [_driver _unit expr] (hsql/call :minute expr)) -(defmethod sql.qp/date [:athena :hour-of-day] [_driver _unit expr] (hsql/call :hour expr)) -(defmethod sql.qp/date [:athena :day-of-month] [_driver _unit expr] (hsql/call :day_of_month expr)) -(defmethod sql.qp/date [:athena :day-of-year] [_driver _unit expr] (hsql/call :day_of_year expr)) -(defmethod sql.qp/date [:athena :month-of-year] [_driver _unit expr] (hsql/call :month expr)) -(defmethod sql.qp/date [:athena :quarter-of-year] [_driver _unit expr] (hsql/call :quarter expr)) +(defmethod sql.qp/date [:athena :minute-of-hour] [_driver _unit expr] (hx/call :minute expr)) +(defmethod sql.qp/date [:athena :hour-of-day] [_driver _unit expr] (hx/call :hour expr)) +(defmethod sql.qp/date [:athena :day-of-month] [_driver _unit expr] (hx/call :day_of_month expr)) +(defmethod sql.qp/date [:athena :day-of-year] [_driver _unit expr] (hx/call :day_of_year expr)) +(defmethod sql.qp/date [:athena :month-of-year] [_driver _unit expr] (hx/call :month expr)) +(defmethod sql.qp/date [:athena :quarter-of-year] [_driver _unit expr] (hx/call :quarter expr)) (defmethod sql.qp/date [:athena :day-of-week] [driver _ expr] - (sql.qp/adjust-day-of-week driver (hsql/call :day_of_week expr))) + (sql.qp/adjust-day-of-week driver (hx/call :day_of_week expr))) (defmethod sql.qp/unix-timestamp->honeysql [:athena :seconds] [_driver _seconds-or-milliseconds expr] - (hsql/call :from_unixtime expr)) + (hx/call :from_unixtime expr)) (defmethod sql.qp/add-interval-honeysql-form :athena [_driver hsql-form amount unit] - (hsql/call :date_add - (hx/literal (name unit)) - (hsql/raw (int amount)) - hsql-form)) + (hx/call :date_add + (hx/literal (name unit)) + (hx/raw (int amount)) + hsql-form)) (defmethod sql.qp/cast-temporal-string [:athena :Coercion/ISO8601->DateTime] [_driver _semantic-type expr] @@ -275,9 +274,9 @@ y (sql.qp/->honeysql driver y)] (case unit (:year :month :quarter :week :day) - (hsql/call :date_diff (hx/literal unit) (date-trunc :day x) (date-trunc :day y)) + (hx/call :date_diff (hx/literal unit) (date-trunc :day x) (date-trunc :day y)) (:hour :minute :second) - (hsql/call :date_diff (hx/literal unit) (hx/->timestamp x) (hx/->timestamp y))))) + (hx/call :date_diff (hx/literal unit) (hx/->timestamp x) (hx/->timestamp y))))) ;; fix to allow integer division to be cast as double (float is not supported by athena) (defmethod sql.qp/->float :athena @@ -287,15 +286,15 @@ ;; Support for median/percentile functions (defmethod sql.qp/->honeysql [:athena :median] [driver [_ arg]] - (hsql/call :approx_percentile (sql.qp/->honeysql driver arg) 0.5)) + (hx/call :approx_percentile (sql.qp/->honeysql driver arg) 0.5)) (defmethod sql.qp/->honeysql [:athena :percentile] [driver [_ arg p]] - (hsql/call :approx_percentile (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver p))) + (hx/call :approx_percentile (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver p))) (defmethod sql.qp/->honeysql [:athena :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_extract (sql.qp/->honeysql driver arg) pattern)) + (hx/call :regexp_extract (sql.qp/->honeysql driver arg) pattern)) ;; keyword function converts database-type variable to a symbol, so we use symbols above to map the types (defn- database-type->base-type-or-warn diff --git a/modules/drivers/athena/test/metabase/driver/athena_test.clj b/modules/drivers/athena/test/metabase/driver/athena_test.clj index 5bd7de2e0df..af1c9792238 100644 --- a/modules/drivers/athena/test/metabase/driver/athena_test.clj +++ b/modules/drivers/athena/test/metabase/driver/athena_test.clj @@ -1,14 +1,15 @@ (ns metabase.driver.athena-test - (:require [clojure.test :refer :all] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [metabase.driver :as driver] - [metabase.driver.athena :as athena] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.public-settings.premium-features :as premium-features] - [metabase.query-processor :as qp] - [metabase.test :as mt])) + (:require + [clojure.test :refer :all] + [honeysql.format :as hformat] + [metabase.driver :as driver] + [metabase.driver.athena :as athena] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.public-settings.premium-features :as premium-features] + [metabase.query-processor :as qp] + [metabase.test :as mt] + [metabase.util.honeysql-extensions :as hx])) (def ^:private nested-schema [{:col_name "key", :data_type "int"} @@ -71,8 +72,8 @@ (testing "We should return TIME and TIMESTAMP WITH TIME ZONE columns correctly" ;; these both come back as `java.sql.type/VARCHAR` for some wacko reason from the JDBC driver, so let's make sure ;; we have code in place to work around that. - (let [timestamp-tz (hsql/raw "timestamp '2022-11-16 04:21:00 US/Pacific'") - time (hsql/raw "time '5:03:00'") + (let [timestamp-tz (hx/raw "timestamp '2022-11-16 04:21:00 US/Pacific'") + time (hx/raw "time '5:03:00'") [sql & args] (hformat/format {:select [[timestamp-tz :timestamp-tz] [time :time]]}) query (-> (mt/native-query {:query sql, :params args}) @@ -102,7 +103,7 @@ ;; apparently you can't cast a TIMESTAMP WITH TIME ZONE to a regular TIMESTAMP. So make sure we're not trying to ;; do that cast. This only applies to Athena v3! I think we're currently testing against v2. When we upgrade this ;; should ensure things continue to work. - (let [literal (hsql/raw "timestamp '2022-11-16 04:21:00 US/Pacific'") + (let [literal (hx/raw "timestamp '2022-11-16 04:21:00 US/Pacific'") [sql & args] (hformat/format {:select [[(sql.qp/add-interval-honeysql-form :athena literal 1 :day) :t] ]}) diff --git a/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk/query_processor.clj b/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk/query_processor.clj index 6339bb3a794..6b598077a53 100644 --- a/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk/query_processor.clj +++ b/modules/drivers/bigquery-cloud-sdk/src/metabase/driver/bigquery_cloud_sdk/query_processor.clj @@ -2,7 +2,6 @@ (:require [clojure.string :as str] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [honeysql.format :as hformat] [java-time :as t] [metabase.driver :as driver] @@ -306,8 +305,8 @@ (let [expr (sql.qp/->honeysql :bigquery-cloud-sdk x)] (if-let [report-zone (when (contains? #{bigquery-type (temporal-type hsql-form)} :timestamp) (qp.timezone/report-timezone-id-if-supported :bigquery-cloud-sdk))] - (with-temporal-type (hsql/call bigquery-type expr (hx/literal report-zone)) target-type) - (with-temporal-type (hsql/call bigquery-type expr) target-type)))) + (with-temporal-type (hx/call bigquery-type expr (hx/literal report-zone)) target-type) + (with-temporal-type (hx/call bigquery-type expr) target-type)))) :else x)))) @@ -343,8 +342,8 @@ :datetime :datetime_trunc :timestamp :timestamp_trunc)] (if-let [report-zone (when (= f :timestamp_trunc) (qp.timezone/report-timezone-id-if-supported :bigquery-cloud-sdk))] - (hformat/to-sql (hsql/call f (->temporal-type t hsql-form) (hsql/raw (name unit)) (hx/literal report-zone))) - (hformat/to-sql (hsql/call f (->temporal-type t hsql-form) (hsql/raw (name unit)))))))) + (hformat/to-sql (hx/call f (->temporal-type t hsql-form) (hx/raw (name unit)) (hx/literal report-zone))) + (hformat/to-sql (hx/call f (->temporal-type t hsql-form) (hx/raw (name unit)))))))) (defmethod temporal-type TruncForm [trunc-form] @@ -380,7 +379,7 @@ (do (assert (valid-time-extract-units unit) (tru "Cannot extract {0} from a TIME field" unit)) - (recur unit (with-temporal-type (hsql/call :timestamp (hsql/call :datetime "1970-01-01" expr)) + (recur unit (with-temporal-type (hx/call :timestamp (hx/call :datetime "1970-01-01" expr)) :timestamp))) ;; timestamp and date both support extract() @@ -388,7 +387,7 @@ (do (assert (valid-date-extract-units unit) (tru "Cannot extract {0} from a DATE field" unit)) - (with-temporal-type (hsql/call :extract unit expr) nil)) + (with-temporal-type (hx/call :extract unit expr) nil)) :timestamp (do @@ -396,8 +395,8 @@ (valid-time-extract-units unit)) (tru "Cannot extract {0} from a DATETIME or TIMESTAMP" unit)) (if-let [report-zone (qp.timezone/report-timezone-id-if-supported :bigquery-cloud-sdk)] - (with-temporal-type (hsql/call :extract unit (->AtTimeZone expr report-zone)) nil) - (with-temporal-type (hsql/call :extract unit expr) nil))) + (with-temporal-type (hx/call :extract unit (->AtTimeZone expr report-zone)) nil) + (with-temporal-type (hx/call :extract unit expr) nil))) ;; for datetimes or anything without a known temporal type, cast to timestamp and go from there (recur unit (->temporal-type :timestamp expr)))) @@ -428,7 +427,7 @@ driver (extract :dayofweek expr) (driver.common/start-of-week-offset driver) - (partial hsql/call (u/qualified-name ::mod)))) + (partial hx/call (u/qualified-name ::mod)))) (defmethod sql.qp/date [:bigquery-cloud-sdk :week] [_ _ expr] @@ -442,17 +441,17 @@ :microseconds :timestamp_micros}] (defmethod sql.qp/unix-timestamp->honeysql [:bigquery-cloud-sdk unix-timestamp-type] [_ _ expr] - (with-temporal-type (hsql/call bigquery-fn expr) :timestamp))) + (with-temporal-type (hx/call bigquery-fn expr) :timestamp))) (defmethod sql.qp/->honeysql [:bigquery-cloud-sdk :convert-timezone] [driver [_ arg target-timezone source-timezone]] - (let [datetime (partial hsql/call :datetime) + (let [datetime (partial hx/call :datetime) hsql-form (sql.qp/->honeysql driver arg) timestamptz? (hx/is-of-type? hsql-form "timestamp")] (sql.u/validate-convert-timezone-args timestamptz? target-timezone source-timezone) (-> (if timestamptz? hsql-form - (hsql/call :timestamp hsql-form (or source-timezone (qp.timezone/results-timezone-id)))) + (hx/call :timestamp hsql-form (or source-timezone (qp.timezone/results-timezone-id)))) (datetime target-timezone) (with-temporal-type :datetime)))) @@ -462,7 +461,7 @@ (defmethod sql.qp/->honeysql [:bigquery-cloud-sdk :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_extract (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_extract (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (defn- percentile->quantile [x] @@ -534,7 +533,7 @@ (defmethod sql.qp/cast-temporal-string [:bigquery-cloud-sdk :Coercion/YYYYMMDDHHMMSSString->Temporal] [_driver _coercion-strategy expr] - (hsql/call :parse_datetime (hx/literal "%Y%m%d%H%M%S") expr)) + (hx/call :parse_datetime (hx/literal "%Y%m%d%H%M%S") expr)) (defmethod sql.qp/->honeysql [:bigquery-cloud-sdk Identifier] [_ identifier] @@ -586,10 +585,10 @@ (sql.qp/datetime-diff driver unit x y))) (defn- timestamp-diff [unit x y] - (hsql/call :timestamp_diff - (->temporal-type :timestamp y) - (->temporal-type :timestamp x) - (hsql/raw (name unit)))) + (hx/call :timestamp_diff + (->temporal-type :timestamp y) + (->temporal-type :timestamp x) + (hx/raw (name unit)))) (defmethod sql.qp/datetime-diff [:bigquery-cloud-sdk :year] [driver _unit x y] @@ -605,15 +604,15 @@ ;; Also `<` and `>` comparisons can only be made on the same type. (let [x' (->temporal-type :datetime x) y' (->temporal-type :datetime y)] - (hx/+ (hsql/call :datetime_diff y' x' (hsql/raw "month")) + (hx/+ (hx/call :datetime_diff y' x' (hx/raw "month")) ;; datetime_diff counts month boundaries not whole months, so we need to adjust ;; if x<y but x>y in the month calendar then subtract one month ;; if x>y but x<y in the month calendar then add one month - (hsql/call + (hx/call :case - (hsql/call :and (hsql/call :< x' y') (hsql/call :> (extract :day x) (extract :day y))) + (hx/call :and (hx/call :< x' y') (hx/call :> (extract :day x) (extract :day y))) -1 - (hsql/call :and (hsql/call :> x' y') (hsql/call :< (extract :day x) (extract :day y))) + (hx/call :and (hx/call :> x' y') (hx/call :< (extract :day x) (extract :day y))) 1 :else 0)))) @@ -728,7 +727,7 @@ (defn- interval [amount unit] ;; todo: can bigquery have an expression here or just a numeric literal? - (hsql/raw (format "INTERVAL %d %s" (int amount) (name unit)))) + (hx/raw (format "INTERVAL %d %s" (int amount) (name unit)))) ;; We can coerce the HoneySQL form this wraps to whatever we want and generate the appropriate SQL. ;; Thus for something like filtering against a relative datetime @@ -747,7 +746,7 @@ (to-sql [_] (let [t (temporal-type hsql-form) add-fn (temporal-type->arithmetic-function t)] - (hformat/to-sql (hsql/call add-fn hsql-form (interval amount unit)))))) + (hformat/to-sql (hx/call add-fn hsql-form (interval amount unit)))))) (defn- add-interval-form [hsql-form amount unit] (let [t (temporal-type hsql-form) @@ -804,8 +803,8 @@ report-zone (when (not= f :current_timestamp) (qp.timezone/report-timezone-id-if-supported :bigquery-cloud-sdk))] (hformat/to-sql (if report-zone - (hsql/call f (hx/literal report-zone)) - (hsql/call f)))))) + (hx/call f (hx/literal report-zone)) + (hx/call f)))))) (defmethod temporal-type CurrentMomentForm [^CurrentMomentForm current-moment] diff --git a/modules/drivers/bigquery-cloud-sdk/test/metabase/driver/bigquery_cloud_sdk/query_processor_test.clj b/modules/drivers/bigquery-cloud-sdk/test/metabase/driver/bigquery_cloud_sdk/query_processor_test.clj index 819aa20037a..b08ea4bebe0 100644 --- a/modules/drivers/bigquery-cloud-sdk/test/metabase/driver/bigquery_cloud_sdk/query_processor_test.clj +++ b/modules/drivers/bigquery-cloud-sdk/test/metabase/driver/bigquery_cloud_sdk/query_processor_test.clj @@ -1,26 +1,27 @@ (ns metabase.driver.bigquery-cloud-sdk.query-processor-test - (:require [clojure.string :as str] - [clojure.test :refer :all] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [java-time :as t] - [metabase.driver :as driver] - [metabase.driver.bigquery-cloud-sdk :as bigquery] - [metabase.driver.bigquery-cloud-sdk.query-processor :as bigquery.qp] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.mbql.util :as mbql.u] - [metabase.models :refer [Database Field Table]] - [metabase.query-processor :as qp] - [metabase.query-processor-test :as qp.test] - [metabase.query-processor.util.add-alias-info :as add] - [metabase.sync :as sync] - [metabase.test :as mt] - [metabase.test.data.bigquery-cloud-sdk :as bigquery.tx] - [metabase.test.util :as tu] - [metabase.test.util.timezone :as test.tz] - [metabase.util :as u] - [metabase.util.honeysql-extensions :as hx] - [toucan.util.test :as tt])) + (:require + [clojure.string :as str] + [clojure.test :refer :all] + [honeysql.core :as hsql] + [honeysql.format :as hformat] + [java-time :as t] + [metabase.driver :as driver] + [metabase.driver.bigquery-cloud-sdk :as bigquery] + [metabase.driver.bigquery-cloud-sdk.query-processor :as bigquery.qp] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.mbql.util :as mbql.u] + [metabase.models :refer [Database Field Table]] + [metabase.query-processor :as qp] + [metabase.query-processor-test :as qp.test] + [metabase.query-processor.util.add-alias-info :as add] + [metabase.sync :as sync] + [metabase.test :as mt] + [metabase.test.data.bigquery-cloud-sdk :as bigquery.tx] + [metabase.test.util :as tu] + [metabase.test.util.timezone :as test.tz] + [metabase.util :as u] + [metabase.util.honeysql-extensions :as hx] + [toucan.util.test :as tt])) (deftest native-query-test (mt/test-driver :bigquery-cloud-sdk @@ -263,13 +264,13 @@ (let [unix-ts (sql.qp/unix-timestamp->honeysql :bigquery-cloud-sdk :seconds :some_field)] {:value unix-ts :type :timestamp - :as {:date (hsql/call :date unix-ts) - :datetime (hsql/call :datetime unix-ts)}}) + :as {:date (hx/call :date unix-ts) + :datetime (hx/call :datetime unix-ts)}}) (let [unix-ts (sql.qp/unix-timestamp->honeysql :bigquery-cloud-sdk :milliseconds :some_field)] {:value unix-ts :type :timestamp - :as {:date (hsql/call :date unix-ts) - :datetime (hsql/call :datetime unix-ts)}})]) + :as {:date (hx/call :date unix-ts) + :datetime (hx/call :datetime unix-ts)}})]) (deftest temporal-type-test (testing "Make sure we can detect temporal types correctly" @@ -344,10 +345,10 @@ ::bigquery.qp/do-not-qualify? true) expected-identifier (case temporal-type :date (hx/with-database-type-info identifier "date") - :datetime (hsql/call :timestamp identifier) + :datetime (hx/call :timestamp identifier) :timestamp (hx/with-database-type-info identifier "timestamp"))]] (testing (format "\ntemporal-type = %s" temporal-type) - (is (= [:= (hsql/call :extract :dayofweek expected-identifier) 1] + (is (= [:= (hx/call :extract :dayofweek expected-identifier) 1] (sql.qp/->honeysql :bigquery-cloud-sdk [:= [:field (:id field) {:temporal-unit :day-of-week ::add/source-table "ABC"}] 1]))))))))))) @@ -481,7 +482,7 @@ (t/local-date-time "2019-11-11T00:00") (t/local-date-time "2019-11-12T00:00")] (between->sql [:between - (with-meta (hsql/raw "field") {:bigquery-cloud-sdk/temporal-type :datetime}) + (with-meta (hx/raw "field") {:bigquery-cloud-sdk/temporal-type :datetime}) (t/local-date "2019-11-11") (t/local-date "2019-11-12")])))) (testing "If first arg has no temporal-type info, should look at next arg" @@ -489,7 +490,7 @@ (t/local-date "2019-11-11") (t/local-date "2019-11-12")] (between->sql [:between - (hsql/raw "field") + (hx/raw "field") (t/local-date "2019-11-11") (t/local-date "2019-11-12")])))) (testing "No need to cast if args agree on temporal type" @@ -497,7 +498,7 @@ (t/local-date "2019-11-11") (t/local-date "2019-11-12")] (between->sql [:between - (with-meta (hsql/raw "field") {:bigquery-cloud-sdk/temporal-type :date}) + (with-meta (hx/raw "field") {:bigquery-cloud-sdk/temporal-type :date}) (t/local-date "2019-11-11") (t/local-date "2019-11-12")])))) (mt/test-driver :bigquery-cloud-sdk diff --git a/modules/drivers/oracle/src/metabase/driver/oracle.clj b/modules/drivers/oracle/src/metabase/driver/oracle.clj index 38de3efd1f1..78b931062c9 100644 --- a/modules/drivers/oracle/src/metabase/driver/oracle.clj +++ b/modules/drivers/oracle/src/metabase/driver/oracle.clj @@ -3,7 +3,6 @@ [clojure.java.jdbc :as jdbc] [clojure.string :as str] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [honeysql.format :as hformat] [java-time :as t] [metabase.config :as config] @@ -16,9 +15,11 @@ [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] [metabase.driver.sql-jdbc.sync.common :as sql-jdbc.sync.common] - [metabase.driver.sql-jdbc.sync.describe-table :as sql-jdbc.describe-table] + [metabase.driver.sql-jdbc.sync.describe-table + :as sql-jdbc.describe-table] [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.sql.query-processor.empty-string-is-null :as sql.qp.empty-string-is-null] + [metabase.driver.sql.query-processor.empty-string-is-null + :as sql.qp.empty-string-is-null] [metabase.driver.sql.util :as sql.u] [metabase.driver.sql.util.unprepare :as unprepare] [metabase.models.secret :as secret] @@ -184,29 +185,29 @@ (trunc :day v) -> TRUNC(v, 'day')" [format-template v] - (-> (hsql/call :trunc v (hx/literal format-template)) + (-> (hx/call :trunc v (hx/literal format-template)) ;; trunc() returns a date -- see https://docs.oracle.com/cd/E11882_01/server.112/e10729/ch4datetime.htm#NLSPG253 (hx/with-database-type-info "date"))) (defmethod sql.qp/date [:oracle :second-of-minute] [_ _ v] (->> v hx/->timestamp - (hsql/call :extract :second) - (hsql/call :floor) + (hx/call :extract :second) + (hx/call :floor) hx/->integer)) (defmethod sql.qp/date [:oracle :minute] [_ _ v] (trunc :mi v)) ;; you can only extract minute + hour from TIMESTAMPs, even though DATEs still have them (WTF), so cast first -(defmethod sql.qp/date [:oracle :minute-of-hour] [_ _ v] (hsql/call :extract :minute (hx/->timestamp v))) +(defmethod sql.qp/date [:oracle :minute-of-hour] [_ _ v] (hx/call :extract :minute (hx/->timestamp v))) (defmethod sql.qp/date [:oracle :hour] [_ _ v] (trunc :hh v)) -(defmethod sql.qp/date [:oracle :hour-of-day] [_ _ v] (hsql/call :extract :hour (hx/->timestamp v))) +(defmethod sql.qp/date [:oracle :hour-of-day] [_ _ v] (hx/call :extract :hour (hx/->timestamp v))) (defmethod sql.qp/date [:oracle :day] [_ _ v] (trunc :dd v)) -(defmethod sql.qp/date [:oracle :day-of-month] [_ _ v] (hsql/call :extract :day v)) +(defmethod sql.qp/date [:oracle :day-of-month] [_ _ v] (hx/call :extract :day v)) ;; [SIC] The format template for truncating to start of week is 'day' in Oracle #WTF (defmethod sql.qp/date [:oracle :month] [_ _ v] (trunc :month v)) -(defmethod sql.qp/date [:oracle :month-of-year] [_ _ v] (hsql/call :extract :month v)) +(defmethod sql.qp/date [:oracle :month-of-year] [_ _ v] (hx/call :extract :month v)) (defmethod sql.qp/date [:oracle :quarter] [_ _ v] (trunc :q v)) (defmethod sql.qp/date [:oracle :year] [_ _ v] (trunc :year v)) -(defmethod sql.qp/date [:oracle :year-of-era] [_ _ v] (hsql/call :extract :year v)) +(defmethod sql.qp/date [:oracle :year-of-era] [_ _ v] (hx/call :extract :year v)) (defmethod sql.qp/date [:oracle :week] [driver _ v] @@ -215,7 +216,7 @@ (defmethod sql.qp/date [:oracle :week-of-year-iso] [_ _ v] ;; the full list of format elements is in https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34924 - (hx/->integer (hsql/call :to_char v (hx/literal :iw)))) + (hx/->integer (hx/call :to_char v (hx/literal :iw)))) (defmethod sql.qp/date [:oracle :day-of-year] [driver _ v] @@ -232,28 +233,28 @@ [driver _ v] (sql.qp/adjust-day-of-week driver - (hx/->integer (hsql/call :to_char v (hx/literal :d))) + (hx/->integer (hx/call :to_char v (hx/literal :d))) (driver.common/start-of-week-offset driver) - (partial hsql/call (u/qualified-name ::mod)))) + (partial hx/call (u/qualified-name ::mod)))) (defmethod sql.qp/current-datetime-honeysql-form :oracle [_] - (-> (hsql/raw "CURRENT_TIMESTAMP") + (-> (hx/raw "CURRENT_TIMESTAMP") (hx/with-database-type-info "timestamp with time zone"))) (defmethod sql.qp/->honeysql [:oracle :convert-timezone] [driver [_ arg target-timezone source-timezone]] (let [expr (sql.qp/->honeysql driver arg) has-timezone? (hx/is-of-type? expr #"timestamp(\(\d\))? with time zone")] - (sql.u/validate-convert-timezone-args has-timezone? target-timezone source-timezone) - (-> (if has-timezone? - expr - (hsql/call :from_tz expr (or source-timezone (qp.timezone/results-timezone-id)))) - (hx/at-time-zone target-timezone) - hx/->timestamp))) + (sql.u/validate-convert-timezone-args has-timezone? target-timezone source-timezone) + (-> (if has-timezone? + expr + (hx/call :from_tz expr (or source-timezone (qp.timezone/results-timezone-id)))) + (hx/at-time-zone target-timezone) + hx/->timestamp))) -(defn- num-to-ds-interval [unit v] (hsql/call :numtodsinterval v (hx/literal unit))) -(defn- num-to-ym-interval [unit v] (hsql/call :numtoyminterval v (hx/literal unit))) +(defn- num-to-ds-interval [unit v] (hx/call :numtodsinterval v (hx/literal unit))) +(defn- num-to-ym-interval [unit v] (hx/call :numtoyminterval v (hx/literal unit))) (def ^:private legacy-max-identifier-length "Maximal identifier length for Oracle < 12.2" @@ -269,18 +270,18 @@ (defmethod sql.qp/->honeysql [:oracle :substring] [driver [_ arg start length]] (if length - (hsql/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)) - (hsql/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start)))) + (hx/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)) + (hx/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start)))) (defmethod sql.qp/->honeysql [:oracle :concat] [driver [_ & args]] (->> args (map (partial sql.qp/->honeysql driver)) - (reduce (partial hsql/call :concat)))) + (reduce (partial hx/call :concat)))) (defmethod sql.qp/->honeysql [:oracle :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (def ^:private timestamp-types #{"timestamp" "timestamp with time zone" "timestamp with local time zone"}) @@ -296,7 +297,7 @@ (hx/cast-unless-type-in "date" (conj timestamp-types "date") hsql-form)) (defn- add-months [hsql-form amount] - (-> (hsql/call :add_months (cast-to-date-if-needed hsql-form) amount) + (-> (hx/call :add_months (cast-to-date-if-needed hsql-form) amount) (hx/with-database-type-info "date"))) (defmethod sql.qp/add-interval-honeysql-form :oracle @@ -310,33 +311,33 @@ :minute (hx/+ (cast-to-timestamp-if-needed hsql-form) (num-to-ds-interval :minute amount)) :hour (hx/+ (cast-to-timestamp-if-needed hsql-form) (num-to-ds-interval :hour amount)) :day (hx/+ (cast-to-date-if-needed hsql-form) (num-to-ds-interval :day amount)) - :week (hx/+ (cast-to-date-if-needed hsql-form) (num-to-ds-interval :day (hx/* amount (hsql/raw 7)))) + :week (hx/+ (cast-to-date-if-needed hsql-form) (num-to-ds-interval :day (hx/* amount (hx/raw 7)))) :year (hx/+ (cast-to-date-if-needed hsql-form) (num-to-ym-interval :year amount)))) (defmethod sql.qp/unix-timestamp->honeysql [:oracle :seconds] [_ _ field-or-value] - (hx/+ (hsql/raw "timestamp '1970-01-01 00:00:00 UTC'") + (hx/+ (hx/raw "timestamp '1970-01-01 00:00:00 UTC'") (num-to-ds-interval :second field-or-value))) (defmethod sql.qp/cast-temporal-string [:oracle :Coercion/ISO8601->DateTime] [_driver _coercion-strategy expr] - (hsql/call :to_timestamp expr "YYYY-MM-DD HH:mi:SS")) + (hx/call :to_timestamp expr "YYYY-MM-DD HH:mi:SS")) (defmethod sql.qp/cast-temporal-string [:oracle :Coercion/ISO8601->Date] [_driver _coercion-strategy expr] - (hsql/call :to_date expr "YYYY-MM-DD")) + (hx/call :to_date expr "YYYY-MM-DD")) (defmethod sql.qp/cast-temporal-string [:oracle :Coercion/YYYYMMDDHHMMSSString->Temporal] [_driver _coercion-strategy expr] - (hsql/call :to_timestamp expr "YYYYMMDDHH24miSS")) + (hx/call :to_timestamp expr "YYYYMMDDHH24miSS")) (defmethod sql.qp/unix-timestamp->honeysql [:oracle :milliseconds] [driver _ field-or-value] - (sql.qp/unix-timestamp->honeysql driver :seconds (hx// field-or-value (hsql/raw 1000)))) + (sql.qp/unix-timestamp->honeysql driver :seconds (hx// field-or-value (hx/raw 1000)))) (defmethod sql.qp/unix-timestamp->honeysql [:oracle :microseconds] [driver _ field-or-value] - (sql.qp/unix-timestamp->honeysql driver :seconds (hx// field-or-value (hsql/raw 1000000)))) + (sql.qp/unix-timestamp->honeysql driver :seconds (hx// field-or-value (hx/raw 1000000)))) (defn- time-zoned-trunc "Same as [[trunc]], but truncates `x` to `unit` in the results timezone @@ -357,7 +358,7 @@ (defmethod sql.qp/datetime-diff [:oracle :month] [_driver _unit x y] - (hsql/call :MONTHS_BETWEEN (time-zoned-trunc :dd y) (time-zoned-trunc :dd x))) + (hx/call :MONTHS_BETWEEN (time-zoned-trunc :dd y) (time-zoned-trunc :dd x))) (defmethod sql.qp/datetime-diff [:oracle :week] [driver _unit x y] @@ -423,7 +424,7 @@ :from [(-> (merge {:select [:*]} honeysql-query) (update :select sql.u/select-clause-deduplicate-aliases))] - :where [:<= (hsql/raw "rownum") value]}) + :where [:<= (hx/raw "rownum") value]}) (defmethod sql.qp/apply-top-level-clause [:oracle :page] [driver _ honeysql-query {{:keys [items page]} :page}] @@ -433,11 +434,11 @@ (sql.qp/apply-top-level-clause driver :limit honeysql-query {:limit items}) ;; if we need to do an offset we have to do double-nesting {:select [:*] - :from [{:select [:__table__.* [(hsql/raw "rownum") :__rownum__]] + :from [{:select [:__table__.* [(hx/raw "rownum") :__rownum__]] :from [[(merge {:select [:*]} honeysql-query) :__table__]] - :where [:<= (hsql/raw "rownum") (+ offset items)]}] + :where [:<= (hx/raw "rownum") (+ offset items)]}] :where [:> :__rownum__ offset]}))) diff --git a/modules/drivers/oracle/test/metabase/driver/oracle_test.clj b/modules/drivers/oracle/test/metabase/driver/oracle_test.clj index 0db00381e57..659008e90ab 100644 --- a/modules/drivers/oracle/test/metabase/driver/oracle_test.clj +++ b/modules/drivers/oracle/test/metabase/driver/oracle_test.clj @@ -1,37 +1,38 @@ (ns metabase.driver.oracle-test "Tests for specific behavior of the Oracle driver." - (:require [clojure.java.jdbc :as jdbc] - [clojure.string :as str] - [clojure.test :refer :all] - [honeysql.core :as hsql] - [metabase.api.common :as api] - [metabase.driver :as driver] - [metabase.driver.oracle :as oracle] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.util :as driver.u] - [metabase.models.database :refer [Database]] - [metabase.models.field :refer [Field]] - [metabase.models.table :refer [Table]] - [metabase.public-settings.premium-features :as premium-features] - [metabase.query-processor :as qp] - [metabase.query-processor-test :as qp.test] - [metabase.query-processor-test.order-by-test :as qp-test.order-by-test] ; used for one SSL connectivity test - [metabase.sync :as sync] - metabase.sync.util - [metabase.test :as mt] - [metabase.test.data.env :as te] - [metabase.test.data.interface :as tx] - [metabase.test.data.oracle :as oracle.tx] - [metabase.test.data.sql :as sql.tx] - [metabase.test.data.sql.ddl :as ddl] - [metabase.test.util :as tu] - [metabase.util :as u] - [metabase.util.honeysql-extensions :as hx] - [toucan.db :as db] - [toucan.util.test :as tt]) - (:import java.util.Base64)) + (:require + [clojure.java.jdbc :as jdbc] + [clojure.string :as str] + [clojure.test :refer :all] + [metabase.api.common :as api] + [metabase.driver :as driver] + [metabase.driver.oracle :as oracle] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.util :as driver.u] + [metabase.models.database :refer [Database]] + [metabase.models.field :refer [Field]] + [metabase.models.table :refer [Table]] + [metabase.public-settings.premium-features :as premium-features] + [metabase.query-processor :as qp] + [metabase.query-processor-test :as qp.test] + [metabase.query-processor-test.order-by-test :as qp-test.order-by-test] + [metabase.sync :as sync] + [metabase.sync.util] + [metabase.test :as mt] + [metabase.test.data.env :as te] + [metabase.test.data.interface :as tx] + [metabase.test.data.oracle :as oracle.tx] + [metabase.test.data.sql :as sql.tx] + [metabase.test.data.sql.ddl :as ddl] + [metabase.test.util :as tu] + [metabase.util :as u] + [metabase.util.honeysql-extensions :as hx] + [toucan.db :as db] + [toucan.util.test :as tt]) + (:import + (java.util Base64))) (deftest connection-details->spec-test (doseq [[^String message expected-spec details] @@ -290,7 +291,7 @@ (id "test_data_categories__via__cat" "name" "varchar2") "BBQ"] :order-by [[(id "id" "number") :asc]]}] - :where [:<= (hsql/raw "rownum") 100]}) + :where [:<= (hx/raw "rownum") 100]}) (#'sql.qp/mbql->honeysql :oracle (qp/preprocess diff --git a/modules/drivers/presto-common/src/metabase/driver/presto_common.clj b/modules/drivers/presto-common/src/metabase/driver/presto_common.clj index 1a7538e36d3..04ab89ed9de 100644 --- a/modules/drivers/presto-common/src/metabase/driver/presto_common.clj +++ b/modules/drivers/presto-common/src/metabase/driver/presto_common.clj @@ -1,23 +1,25 @@ (ns metabase.driver.presto-common "Abstract common driver for Presto. It only defines SQL generation logic and doesn't involve the transport/execution mechanism for actually connecting to Presto." - (:require [buddy.core.codecs :as codecs] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [honeysql.helpers :as hh] - [java-time :as t] - [metabase.driver :as driver] - [metabase.driver.common :as driver.common] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.sql.util :as sql.u] - [metabase.driver.sql.util.unprepare :as unprepare] - [metabase.query-processor.timezone :as qp.timezone] - [metabase.util :as u] - [metabase.util.date-2 :as u.date] - [metabase.util.honeysql-extensions :as hx]) - (:import java.sql.Time - [java.time OffsetDateTime ZonedDateTime])) + (:require + [buddy.core.codecs :as codecs] + [honeysql.core :as hsql] + [honeysql.format :as hformat] + [honeysql.helpers :as hh] + [java-time :as t] + [metabase.driver :as driver] + [metabase.driver.common :as driver.common] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.sql.util :as sql.u] + [metabase.driver.sql.util.unprepare :as unprepare] + [metabase.query-processor.timezone :as qp.timezone] + [metabase.util :as u] + [metabase.util.date-2 :as u.date] + [metabase.util.honeysql-extensions :as hx]) + (:import + (java.sql Time) + (java.time OffsetDateTime ZonedDateTime))) (defmethod driver/database-supports? [:presto-common :now] [_driver _feat _db] true) @@ -56,7 +58,7 @@ (defmethod sql.qp/add-interval-honeysql-form :presto-common [_ hsql-form amount unit] - (hsql/call :date_add (hx/literal unit) amount hsql-form)) + (hx/call :date_add (hx/literal unit) amount hsql-form)) (defn describe-catalog-sql "The SHOW SCHEMAS statement that will list all schemas for the given `catalog`." @@ -86,16 +88,16 @@ (defmethod sql.qp/cast-temporal-string [:presto-common :Coercion/YYYYMMDDHHMMSSString->Temporal] [_ _coercion-strategy expr] - (hsql/call :date_parse expr (hx/literal "%Y%m%d%H%i%s"))) + (hx/call :date_parse expr (hx/literal "%Y%m%d%H%i%s"))) (defmethod sql.qp/cast-temporal-byte [:presto-common :Coercion/YYYYMMDDHHMMSSBytes->Temporal] [driver _coercion-strategy expr] (sql.qp/cast-temporal-string driver :Coercion/YYYYMMDDHHMMSSString->Temporal - (hsql/call :from_utf8 expr))) + (hx/call :from_utf8 expr))) (defmethod sql.qp/->honeysql [:presto-common Boolean] [_ bool] - (hsql/raw (if bool "TRUE" "FALSE"))) + (hx/raw (if bool "TRUE" "FALSE"))) (defmethod sql.qp/->honeysql [:presto-common :time] [_ [_ t]] @@ -107,15 +109,15 @@ (defmethod sql.qp/->honeysql [:presto-common :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_extract (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_extract (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (defmethod sql.qp/->honeysql [:presto-common :median] [driver [_ arg]] - (hsql/call :approx_percentile (sql.qp/->honeysql driver arg) 0.5)) + (hx/call :approx_percentile (sql.qp/->honeysql driver arg) 0.5)) (defmethod sql.qp/->honeysql [:presto-common :percentile] [driver [_ arg p]] - (hsql/call :approx_percentile (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver p))) + (hx/call :approx_percentile (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver p))) ;; Presto mod is a function like mod(x, y) rather than an operator like x mod y (defmethod hformat/fn-handler (u/qualified-name ::mod) @@ -164,7 +166,7 @@ :allow-dashed-names? true :quoting :ansi)))] (-> (apply hh/select (map last (:select honeysql-query))) - (hh/from (hh/merge-select honeysql-query [(hsql/raw over-clause) :__rownum__])) + (hh/from (hh/merge-select honeysql-query [(hx/raw over-clause) :__rownum__])) (hh/where [:> :__rownum__ offset]) (hh/limit items)))))) @@ -172,35 +174,35 @@ [_] (hx/with-database-type-info :%now "timestamp with time zone")) -(defn- date-diff [unit a b] (hsql/call :date_diff (hx/literal unit) a b)) -(defn- date-trunc [unit x] (hsql/call :date_trunc (hx/literal unit) x)) +(defn- date-diff [unit a b] (hx/call :date_diff (hx/literal unit) a b)) +(defn- date-trunc [unit x] (hx/call :date_trunc (hx/literal unit) x)) (defmethod sql.qp/date [:presto-common :default] [_ _ expr] expr) (defmethod sql.qp/date [:presto-common :minute] [_ _ expr] (date-trunc :minute expr)) -(defmethod sql.qp/date [:presto-common :minute-of-hour] [_ _ expr] (hsql/call :minute expr)) +(defmethod sql.qp/date [:presto-common :minute-of-hour] [_ _ expr] (hx/call :minute expr)) (defmethod sql.qp/date [:presto-common :hour] [_ _ expr] (date-trunc :hour expr)) -(defmethod sql.qp/date [:presto-common :hour-of-day] [_ _ expr] (hsql/call :hour expr)) +(defmethod sql.qp/date [:presto-common :hour-of-day] [_ _ expr] (hx/call :hour expr)) (defmethod sql.qp/date [:presto-common :day] [_ _ expr] (date-trunc :day expr)) -(defmethod sql.qp/date [:presto-common :day-of-month] [_ _ expr] (hsql/call :day expr)) -(defmethod sql.qp/date [:presto-common :day-of-year] [_ _ expr] (hsql/call :day_of_year expr)) +(defmethod sql.qp/date [:presto-common :day-of-month] [_ _ expr] (hx/call :day expr)) +(defmethod sql.qp/date [:presto-common :day-of-year] [_ _ expr] (hx/call :day_of_year expr)) (defmethod sql.qp/date [:presto-common :day-of-week] [driver _ expr] - (sql.qp/adjust-day-of-week driver (hsql/call :day_of_week expr))) + (sql.qp/adjust-day-of-week driver (hx/call :day_of_week expr))) (defmethod sql.qp/date [:presto-common :week] [driver _ expr] (sql.qp/adjust-start-of-week driver (partial date-trunc :week) expr)) (defmethod sql.qp/date [:presto-common :month] [_ _ expr] (date-trunc :month expr)) -(defmethod sql.qp/date [:presto-common :month-of-year] [_ _ expr] (hsql/call :month expr)) +(defmethod sql.qp/date [:presto-common :month-of-year] [_ _ expr] (hx/call :month expr)) (defmethod sql.qp/date [:presto-common :quarter] [_ _ expr] (date-trunc :quarter expr)) -(defmethod sql.qp/date [:presto-common :quarter-of-year] [_ _ expr] (hsql/call :quarter expr)) +(defmethod sql.qp/date [:presto-common :quarter-of-year] [_ _ expr] (hx/call :quarter expr)) (defmethod sql.qp/date [:presto-common :year] [_ _ expr] (date-trunc :year expr)) (defmethod sql.qp/unix-timestamp->honeysql [:presto-common :seconds] [_ _ expr] - (hsql/call :from_unixtime expr)) + (hx/call :from_unixtime expr)) (defn ->date "Same as [[hx/->date]], but truncates `x` to the date in the results time zone." diff --git a/modules/drivers/presto-jdbc/src/metabase/driver/presto_jdbc.clj b/modules/drivers/presto-jdbc/src/metabase/driver/presto_jdbc.clj index 8d56570c7c3..8e49a08200b 100644 --- a/modules/drivers/presto-jdbc/src/metabase/driver/presto_jdbc.clj +++ b/modules/drivers/presto-jdbc/src/metabase/driver/presto_jdbc.clj @@ -1,34 +1,37 @@ (ns metabase.driver.presto-jdbc "Presto JDBC driver. See https://prestodb.io/docs/current/ for complete dox." - (:require [clojure.java.jdbc :as jdbc] - [clojure.set :as set] - [clojure.string :as str] - [clojure.tools.logging :as log] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [java-time :as t] - [metabase.db.spec :as mdb.spec] - [metabase.driver :as driver] - [metabase.driver.presto-common :as presto-common] - [metabase.driver.sql-jdbc.common :as sql-jdbc.common] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] - [metabase.driver.sql-jdbc.sync.describe-database :as sql-jdbc.describe-database] - [metabase.driver.sql.parameters.substitution :as sql.params.substitution] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.models.secret :as secret] - [metabase.query-processor.timezone :as qp.timezone] - [metabase.util :as u] - [metabase.util.date-2 :as u.date] - [metabase.util.honeysql-extensions :as hx] - [metabase.util.i18n :refer [trs]]) - (:import com.facebook.presto.jdbc.PrestoConnection - com.mchange.v2.c3p0.C3P0ProxyConnection - [java.sql Connection PreparedStatement ResultSet ResultSetMetaData Time Types] - [java.time LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime] - java.time.format.DateTimeFormatter - [java.time.temporal ChronoField Temporal])) + (:require + [clojure.java.jdbc :as jdbc] + [clojure.set :as set] + [clojure.string :as str] + [clojure.tools.logging :as log] + [honeysql.format :as hformat] + [java-time :as t] + [metabase.db.spec :as mdb.spec] + [metabase.driver :as driver] + [metabase.driver.presto-common :as presto-common] + [metabase.driver.sql-jdbc.common :as sql-jdbc.common] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] + [metabase.driver.sql-jdbc.sync.describe-database + :as sql-jdbc.describe-database] + [metabase.driver.sql.parameters.substitution + :as sql.params.substitution] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.models.secret :as secret] + [metabase.query-processor.timezone :as qp.timezone] + [metabase.util :as u] + [metabase.util.date-2 :as u.date] + [metabase.util.honeysql-extensions :as hx] + [metabase.util.i18n :refer [trs]]) + (:import + (com.facebook.presto.jdbc PrestoConnection) + (com.mchange.v2.c3p0 C3P0ProxyConnection) + (java.sql Connection PreparedStatement ResultSet ResultSetMetaData Time Types) + (java.time LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime) + (java.time.format DateTimeFormatter) + (java.time.temporal ChronoField Temporal))) (driver/register! :presto-jdbc, :parent #{:presto-common :sql-jdbc @@ -43,7 +46,7 @@ (defmethod sql.qp/->honeysql [:presto-jdbc :log] [driver [_ field]] ;; recent Presto versions have a `log10` function (not `log`) - (hsql/call :log10 (sql.qp/->honeysql driver field))) + (hx/call :log10 (sql.qp/->honeysql driver field))) (defmethod sql.qp/->honeysql [:presto-jdbc :count-where] [driver [_ pred]] @@ -77,13 +80,13 @@ type-info (hx/type-info expr) db-type (hx/type-info->db-type type-info)] (if (and ;; AT TIME ZONE is only valid on these Presto types; if applied to something else (ex: `date`), then - ;; an error will be thrown by the query analyzer - (contains? #{"timestamp" "timestamp with time zone" "time" "time with time zone"} db-type) - ;; if one has already been set, don't do so again - (not (::in-report-zone? (meta expr))) - report-zone) + ;; an error will be thrown by the query analyzer + (contains? #{"timestamp" "timestamp with time zone" "time" "time with time zone"} db-type) + ;; if one has already been set, don't do so again + (not (::in-report-zone? (meta expr))) + report-zone) (-> (hx/with-database-type-info (hx/at-time-zone expr report-zone) timestamp-with-time-zone-db-type) - (vary-meta assoc ::in-report-zone? true)) + (vary-meta assoc ::in-report-zone? true)) expr))) ;; most date extraction and bucketing functions need to account for report timezone @@ -94,79 +97,79 @@ (defmethod sql.qp/date [:presto-jdbc :minute] [_ _ expr] - (hsql/call :date_trunc (hx/literal :minute) (in-report-zone expr))) + (hx/call :date_trunc (hx/literal :minute) (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :minute-of-hour] [_ _ expr] - (hsql/call :minute (in-report-zone expr))) + (hx/call :minute (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :hour] [_ _ expr] - (hsql/call :date_trunc (hx/literal :hour) (in-report-zone expr))) + (hx/call :date_trunc (hx/literal :hour) (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :hour-of-day] [_ _ expr] - (hsql/call :hour (in-report-zone expr))) + (hx/call :hour (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :day] [_ _ expr] - (hsql/call :date (in-report-zone expr))) + (hx/call :date (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :day-of-week] [_ _ expr] - (sql.qp/adjust-day-of-week :presto-jdbc (hsql/call :day_of_week (in-report-zone expr)))) + (sql.qp/adjust-day-of-week :presto-jdbc (hx/call :day_of_week (in-report-zone expr)))) (defmethod sql.qp/date [:presto-jdbc :day-of-month] [_ _ expr] - (hsql/call :day (in-report-zone expr))) + (hx/call :day (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :day-of-year] [_ _ expr] - (hsql/call :day_of_year (in-report-zone expr))) + (hx/call :day_of_year (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :week] [_ _ expr] - (sql.qp/adjust-start-of-week :presto-jdbc (partial hsql/call :date_trunc (hx/literal :week)) (in-report-zone expr))) + (sql.qp/adjust-start-of-week :presto-jdbc (partial hx/call :date_trunc (hx/literal :week)) (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :month] [_ _ expr] - (hsql/call :date_trunc (hx/literal :month) (in-report-zone expr))) + (hx/call :date_trunc (hx/literal :month) (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :month-of-year] [_ _ expr] - (hsql/call :month (in-report-zone expr))) + (hx/call :month (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :quarter] [_ _ expr] - (hsql/call :date_trunc (hx/literal :quarter) (in-report-zone expr))) + (hx/call :date_trunc (hx/literal :quarter) (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :quarter-of-year] [_ _ expr] - (hsql/call :quarter (in-report-zone expr))) + (hx/call :quarter (in-report-zone expr))) (defmethod sql.qp/date [:presto-jdbc :year] [_ _ expr] - (hsql/call :date_trunc (hx/literal :year) (in-report-zone expr))) + (hx/call :date_trunc (hx/literal :year) (in-report-zone expr))) (defmethod sql.qp/unix-timestamp->honeysql [:presto-jdbc :seconds] [_ _ expr] (let [report-zone (qp.timezone/report-timezone-id-if-supported :presto-jdbc)] - (hsql/call :from_unixtime expr (hx/literal (or report-zone "UTC"))))) + (hx/call :from_unixtime expr (hx/literal (or report-zone "UTC"))))) (defmethod sql.qp/unix-timestamp->honeysql [:presto-jdbc :milliseconds] [_ _ expr] ;; from_unixtime doesn't support milliseconds directly, but we can add them back in (let [report-zone (qp.timezone/report-timezone-id-if-supported :presto-jdbc) - millis (hsql/call (u/qualified-name ::mod) expr 1000)] - (hsql/call :date_add - (hx/literal "millisecond") - millis - (hsql/call :from_unixtime (hsql/call :/ expr 1000) (hx/literal (or report-zone "UTC")))))) + millis (hx/call (u/qualified-name ::mod) expr 1000)] + (hx/call :date_add + (hx/literal "millisecond") + millis + (hx/call :from_unixtime (hx/call :/ expr 1000) (hx/literal (or report-zone "UTC")))))) (defmethod sql.qp/unix-timestamp->honeysql [:presto-jdbc :microseconds] [driver _ expr] ;; Presto can't even represent microseconds, so convert to millis and call that version - (sql.qp/unix-timestamp->honeysql driver :milliseconds (hsql/call :/ expr 1000))) + (sql.qp/unix-timestamp->honeysql driver :milliseconds (hx/call :/ expr 1000))) (defmethod sql.qp/current-datetime-honeysql-form :presto-jdbc [_] diff --git a/modules/drivers/presto-jdbc/test/metabase/driver/presto_jdbc_test.clj b/modules/drivers/presto-jdbc/test/metabase/driver/presto_jdbc_test.clj index 12800a32895..00d2d987400 100644 --- a/modules/drivers/presto-jdbc/test/metabase/driver/presto_jdbc_test.clj +++ b/modules/drivers/presto-jdbc/test/metabase/driver/presto_jdbc_test.clj @@ -1,25 +1,27 @@ (ns metabase.driver.presto-jdbc-test - (:require [clojure.java.jdbc :as jdbc] - [clojure.test :refer :all] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [java-time :as t] - [metabase.api.database :as api.database] - [metabase.db.metadata-queries :as metadata-queries] - [metabase.driver :as driver] - [metabase.driver.presto-jdbc :as presto-jdbc] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.models.database :refer [Database]] - [metabase.models.field :refer [Field]] - [metabase.models.table :as table :refer [Table]] - [metabase.query-processor :as qp] - [metabase.sync :as sync] - [metabase.test :as mt] - [metabase.test.data.presto-jdbc :as data.presto-jdbc] - [metabase.test.fixtures :as fixtures] - [toucan.db :as db]) - (:import java.io.File)) + (:require + [clojure.java.jdbc :as jdbc] + [clojure.test :refer :all] + [honeysql.format :as hformat] + [java-time :as t] + [metabase.api.database :as api.database] + [metabase.db.metadata-queries :as metadata-queries] + [metabase.driver :as driver] + [metabase.driver.presto-jdbc :as presto-jdbc] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.models.database :refer [Database]] + [metabase.models.field :refer [Field]] + [metabase.models.table :as table :refer [Table]] + [metabase.query-processor :as qp] + [metabase.sync :as sync] + [metabase.test :as mt] + [metabase.test.data.presto-jdbc :as data.presto-jdbc] + [metabase.test.fixtures :as fixtures] + [metabase.util.honeysql-extensions :as hx] + [toucan.db :as db]) + (:import + (java.io File))) (use-fixtures :once (fixtures/initialize :db)) @@ -87,7 +89,7 @@ (is (= {:select ["name" "id"] :from [{:select [[:default.categories.name "name"] [:default.categories.id "id"] - [(hsql/raw "row_number() OVER (ORDER BY \"default\".\"categories\".\"id\" ASC)") + [(hx/raw "row_number() OVER (ORDER BY \"default\".\"categories\".\"id\" ASC)") :__rownum__]] :from [:default.categories] :order-by [[:default.categories.id :asc]]}] @@ -162,8 +164,8 @@ (testing "unix-timestamp with microsecond precision" (is (= [(str "date_add('millisecond', mod((1623963256123456 / 1000), 1000)," " from_unixtime(((1623963256123456 / 1000) / 1000), 'UTC'))")] - (-> (sql.qp/unix-timestamp->honeysql :presto-jdbc :microseconds (hsql/raw 1623963256123456)) - (hformat/format))))))) + (-> (sql.qp/unix-timestamp->honeysql :presto-jdbc :microseconds (hx/raw 1623963256123456)) + (hformat/format))))))) (defn- clone-db-details "Clones the details of the current DB ensuring fresh copies for the secrets diff --git a/modules/drivers/presto/test/metabase/driver/presto_test.clj b/modules/drivers/presto/test/metabase/driver/presto_test.clj index 4c8bd111977..124506ce654 100644 --- a/modules/drivers/presto/test/metabase/driver/presto_test.clj +++ b/modules/drivers/presto/test/metabase/driver/presto_test.clj @@ -1,24 +1,25 @@ (ns metabase.driver.presto-test - (:require [clj-http.client :as http] - [clojure.core.async :as a] - [clojure.string :as str] - [clojure.test :refer :all] - [honeysql.core :as hsql] - [java-time :as t] - [metabase.db.metadata-queries :as metadata-queries] - [metabase.driver :as driver] - [metabase.driver.presto :as presto] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.util :as driver.u] - [metabase.models.database :refer [Database]] - [metabase.models.field :refer [Field]] - [metabase.models.table :as table :refer [Table]] - [metabase.query-processor :as qp] - [metabase.test :as mt] - [metabase.test.fixtures :as fixtures] - [metabase.util :as u] - [schema.core :as s] - [toucan.db :as db])) + (:require + [clj-http.client :as http] + [clojure.core.async :as a] + [clojure.string :as str] + [clojure.test :refer :all] + [java-time :as t] + [metabase.db.metadata-queries :as metadata-queries] + [metabase.driver :as driver] + [metabase.driver.presto :as presto] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.util :as driver.u] + [metabase.models.database :refer [Database]] + [metabase.models.field :refer [Field]] + [metabase.models.table :as table :refer [Table]] + [metabase.query-processor :as qp] + [metabase.test :as mt] + [metabase.test.fixtures :as fixtures] + [metabase.util :as u] + [metabase.util.honeysql-extensions :as hx] + [schema.core :as s] + [toucan.db :as db])) (use-fixtures :once (fixtures/initialize :db)) @@ -132,7 +133,7 @@ (is (= {:select ["name" "id"] :from [{:select [[:default.categories.name "name"] [:default.categories.id "id"] - [(hsql/raw "row_number() OVER (ORDER BY \"default\".\"categories\".\"id\" ASC)") + [(hx/raw "row_number() OVER (ORDER BY \"default\".\"categories\".\"id\" ASC)") :__rownum__]] :from [:default.categories] :order-by [[:default.categories.id :asc]]}] diff --git a/modules/drivers/redshift/src/metabase/driver/redshift.clj b/modules/drivers/redshift/src/metabase/driver/redshift.clj index 979149e9414..bf4f204bb0a 100644 --- a/modules/drivers/redshift/src/metabase/driver/redshift.clj +++ b/modules/drivers/redshift/src/metabase/driver/redshift.clj @@ -1,27 +1,29 @@ (ns metabase.driver.redshift "Amazon Redshift Driver." - (:require [cheshire.core :as json] - [clojure.java.jdbc :as jdbc] - [clojure.tools.logging :as log] - [honeysql.core :as hsql] - [java-time :as t] - [metabase.driver :as driver] - [metabase.driver.common :as driver.common] - [metabase.driver.sql-jdbc.common :as sql-jdbc.common] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql-jdbc.sync.describe-table :as sql-jdbc.describe-table] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.mbql.util :as mbql.u] - [metabase.public-settings :as public-settings] - [metabase.query-processor.store :as qp.store] - [metabase.query-processor.util :as qp.util] - [metabase.util.honeysql-extensions :as hx] - [metabase.util.i18n :refer [trs]]) - (:import [java.sql Connection PreparedStatement ResultSet Types] - java.time.OffsetTime)) + (:require + [cheshire.core :as json] + [clojure.java.jdbc :as jdbc] + [clojure.tools.logging :as log] + [java-time :as t] + [metabase.driver :as driver] + [metabase.driver.common :as driver.common] + [metabase.driver.sql-jdbc.common :as sql-jdbc.common] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql-jdbc.sync.describe-table + :as sql-jdbc.describe-table] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.mbql.util :as mbql.u] + [metabase.public-settings :as public-settings] + [metabase.query-processor.store :as qp.store] + [metabase.query-processor.util :as qp.util] + [metabase.util.honeysql-extensions :as hx] + [metabase.util.i18n :refer [trs]]) + (:import + (java.sql Connection PreparedStatement ResultSet Types) + (java.time OffsetTime))) (driver/register! :redshift, :parent #{:postgres ::sql-jdbc.legacy/use-legacy-classes-for-read-and-set}) @@ -108,14 +110,14 @@ (defmethod sql.qp/add-interval-honeysql-form :redshift [_ hsql-form amount unit] (let [hsql-form (hx/->timestamp hsql-form)] - (-> (hsql/call :dateadd (hx/literal unit) amount hsql-form) + (-> (hx/call :dateadd (hx/literal unit) amount hsql-form) (hx/with-type-info (hx/type-info hsql-form))))) (defmethod sql.qp/unix-timestamp->honeysql [:redshift :seconds] [_ _ expr] - (hx/+ (hsql/raw "TIMESTAMP '1970-01-01T00:00:00Z'") + (hx/+ (hx/raw "TIMESTAMP '1970-01-01T00:00:00Z'") (hx/* expr - (hsql/raw "INTERVAL '1 second'")))) + (hx/raw "INTERVAL '1 second'")))) (defmethod sql.qp/current-datetime-honeysql-form :redshift [_] @@ -169,39 +171,39 @@ (defmethod sql.qp/->honeysql [:redshift :regex-match-first] [driver [_ arg pattern]] - (hsql/call - :regexp_substr - (sql.qp/->honeysql driver arg) - ;; the parameter to REGEXP_SUBSTR can only be a string literal; neither prepared statement parameters nor encoding/ - ;; decoding functions seem to work (fails with java.sql.SQLExcecption: "The pattern must be a valid UTF-8 literal - ;; character expression"), hence we will use a different function to safely escape it before splicing here - (hsql/raw (quote-literal-for-database (qp.store/database) pattern)))) + (hx/call + :regexp_substr + (sql.qp/->honeysql driver arg) + ;; the parameter to REGEXP_SUBSTR can only be a string literal; neither prepared statement parameters nor encoding/ + ;; decoding functions seem to work (fails with java.sql.SQLExcecption: "The pattern must be a valid UTF-8 literal + ;; character expression"), hence we will use a different function to safely escape it before splicing here + (hx/raw (quote-literal-for-database (qp.store/database) pattern)))) (defmethod sql.qp/->honeysql [:redshift :replace] [driver [_ arg pattern replacement]] - (hsql/call - :replace - (sql.qp/->honeysql driver arg) - (sql.qp/->honeysql driver pattern) - (sql.qp/->honeysql driver replacement))) + (hx/call + :replace + (sql.qp/->honeysql driver arg) + (sql.qp/->honeysql driver pattern) + (sql.qp/->honeysql driver replacement))) (defmethod sql.qp/->honeysql [:redshift :concat] [driver [_ & args]] (->> args (map (partial sql.qp/->honeysql driver)) - (reduce (partial hsql/call :concat)))) + (reduce (partial hx/call :concat)))) (defmethod sql.qp/->honeysql [:redshift :concat] [driver [_ & args]] (->> args (map (partial sql.qp/->honeysql driver)) - (reduce (partial hsql/call :concat)))) + (reduce (partial hx/call :concat)))) (defn- extract [unit temporal] - (hsql/call :extract (format "'%s'" (name unit)) temporal)) + (hx/call :extract (format "'%s'" (name unit)) temporal)) (defn- datediff [unit x y] - (hsql/call :datediff (hsql/raw (name unit)) x y)) + (hx/call :datediff (hx/raw (name unit)) x y)) (defmethod sql.qp/->honeysql [:redshift :datetime-diff] [driver [_ x y unit]] @@ -227,12 +229,12 @@ [_driver _unit x y] (hx/+ (datediff :month x y) ;; redshift's datediff counts month boundaries not whole months, so we need to adjust - (hsql/call + (hx/call :case ;; if x<y but x>y in the month calendar then subtract one month - (hsql/call :and (hsql/call :< x y) (hsql/call :> (extract :day x) (extract :day y))) -1 + (hx/call :and (hx/call :< x y) (hx/call :> (extract :day x) (extract :day y))) -1 ;; if x>y but x<y in the month calendar then add one month - (hsql/call :and (hsql/call :> x y) (hsql/call :< (extract :day x) (extract :day y))) 1 + (hx/call :and (hx/call :> x y) (hx/call :< (extract :day x) (extract :day y))) 1 :else 0))) (defmethod sql.qp/datetime-diff [:redshift :week] diff --git a/modules/drivers/snowflake/src/metabase/driver/snowflake.clj b/modules/drivers/snowflake/src/metabase/driver/snowflake.clj index 23fa4f4ae0d..b41f94b3512 100644 --- a/modules/drivers/snowflake/src/metabase/driver/snowflake.clj +++ b/modules/drivers/snowflake/src/metabase/driver/snowflake.clj @@ -5,7 +5,6 @@ [clojure.set :as set] [clojure.string :as str] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [java-time :as t] [medley.core :as m] [metabase.driver :as driver] @@ -173,9 +172,9 @@ :OBJECT :type/Dictionary :ARRAY :type/*} base-type)) -(defmethod sql.qp/unix-timestamp->honeysql [:snowflake :seconds] [_ _ expr] (hsql/call :to_timestamp expr)) -(defmethod sql.qp/unix-timestamp->honeysql [:snowflake :milliseconds] [_ _ expr] (hsql/call :to_timestamp expr 3)) -(defmethod sql.qp/unix-timestamp->honeysql [:snowflake :microseconds] [_ _ expr] (hsql/call :to_timestamp expr 6)) +(defmethod sql.qp/unix-timestamp->honeysql [:snowflake :seconds] [_ _ expr] (hx/call :to_timestamp expr)) +(defmethod sql.qp/unix-timestamp->honeysql [:snowflake :milliseconds] [_ _ expr] (hx/call :to_timestamp expr 3)) +(defmethod sql.qp/unix-timestamp->honeysql [:snowflake :microseconds] [_ _ expr] (hx/call :to_timestamp expr 6)) (defmethod sql.qp/current-datetime-honeysql-form :snowflake [_] @@ -183,13 +182,13 @@ (defmethod sql.qp/add-interval-honeysql-form :snowflake [_ hsql-form amount unit] - (hsql/call :dateadd - (hsql/raw (name unit)) - (hsql/raw (int amount)) - (hx/->timestamp hsql-form))) + (hx/call :dateadd + (hx/raw (name unit)) + (hx/raw (int amount)) + (hx/->timestamp hsql-form))) -(defn- extract [unit expr] (hsql/call :date_part unit (hx/->timestamp expr))) -(defn- date-trunc [unit expr] (hsql/call :date_trunc unit (hx/->timestamp expr))) +(defn- extract [unit expr] (hx/call :date_part unit (hx/->timestamp expr))) +(defn- date-trunc [unit expr] (hx/call :date_trunc unit (hx/->timestamp expr))) (defmethod sql.qp/date [:snowflake :default] [_ _ expr] expr) (defmethod sql.qp/date [:snowflake :minute] [_ _ expr] (date-trunc :minute expr)) @@ -236,35 +235,35 @@ [unit x y] (let [x (cond->> x (hx/is-of-type? x "timestamptz") - (hsql/call :convert_timezone (qp.timezone/results-timezone-id))) + (hx/call :convert_timezone (qp.timezone/results-timezone-id))) y (cond->> y (hx/is-of-type? y "timestamptz") - (hsql/call :convert_timezone (qp.timezone/results-timezone-id)))] - (hsql/call :datediff (hsql/raw (name unit)) x y))) + (hx/call :convert_timezone (qp.timezone/results-timezone-id)))] + (hx/call :datediff (hx/raw (name unit)) x y))) (defn- time-zoned-extract "Same as `extract` but converts the arg to the results time zone if it's a timestamptz." [unit x] (let [x (cond->> x (hx/is-of-type? x "timestamptz") - (hsql/call :convert_timezone (qp.timezone/results-timezone-id)))] + (hx/call :convert_timezone (qp.timezone/results-timezone-id)))] (extract unit x))) (defn- sub-day-datediff "Same as snowflake's `datediff`, but accurate to the millisecond for sub-day units." [unit x y] - (let [milliseconds (hsql/call :datediff (hsql/raw "milliseconds") x y)] + (let [milliseconds (hx/call :datediff (hx/raw "milliseconds") x y)] ;; millseconds needs to be cast to float because division rounds incorrectly with large integers - (hsql/call :trunc (hx// (hx/cast :float milliseconds) - (case unit :hour 3600000 :minute 60000 :second 1000))))) + (hx/call :trunc (hx// (hx/cast :float milliseconds) + (case unit :hour 3600000 :minute 60000 :second 1000))))) (defmethod sql.qp/datetime-diff [:snowflake :year] [driver _unit x y] - (hsql/call :trunc (hx// (sql.qp/datetime-diff driver :month x y) 12))) + (hx/call :trunc (hx// (sql.qp/datetime-diff driver :month x y) 12))) (defmethod sql.qp/datetime-diff [:snowflake :quarter] [driver _unit x y] - (hsql/call :trunc (hx// (sql.qp/datetime-diff driver :month x y) 3))) + (hx/call :trunc (hx// (sql.qp/datetime-diff driver :month x y) 3))) (defmethod sql.qp/datetime-diff [:snowflake :month] [_driver _unit x y] @@ -272,17 +271,17 @@ ;; datediff counts month boundaries not whole months, so we need to adjust ;; if x<y but x>y in the month calendar then subtract one month ;; if x>y but x<y in the month calendar then add one month - (hsql/call + (hx/call :case - (hsql/call :and (hsql/call :< x y) (hsql/call :> (time-zoned-extract :day x) (time-zoned-extract :day y))) + (hx/call :and (hx/call :< x y) (hx/call :> (time-zoned-extract :day x) (time-zoned-extract :day y))) -1 - (hsql/call :and (hsql/call :> x y) (hsql/call :< (time-zoned-extract :day x) (time-zoned-extract :day y))) + (hx/call :and (hx/call :> x y) (hx/call :< (time-zoned-extract :day x) (time-zoned-extract :day y))) 1 :else 0))) (defmethod sql.qp/datetime-diff [:snowflake :week] [_driver _unit x y] - (hsql/call :trunc (hx// (time-zoned-datediff :day x y) 7))) + (hx/call :trunc (hx// (time-zoned-datediff :day x y) 7))) (defmethod sql.qp/datetime-diff [:snowflake :day] [_driver _unit x y] @@ -294,7 +293,7 @@ (defmethod sql.qp/->honeysql [:snowflake :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (defmethod sql.qp/->honeysql [:snowflake :median] [driver [_ arg]] @@ -357,10 +356,10 @@ timestamptz? (hx/is-of-type? hsql-form "timestamptz")] (sql.u/validate-convert-timezone-args timestamptz? target-timezone source-timezone) (-> (if timestamptz? - (hsql/call :convert_timezone target-timezone hsql-form) + (hx/call :convert_timezone target-timezone hsql-form) (->> hsql-form - (hsql/call :convert_timezone (or source-timezone (qp.timezone/results-timezone-id)) target-timezone) - (hsql/call :to_timestamp_ntz))) + (hx/call :convert_timezone (or source-timezone (qp.timezone/results-timezone-id)) target-timezone) + (hx/call :to_timestamp_ntz))) (hx/with-database-type-info "timestampntz")))) (defmethod driver/table-rows-seq :snowflake diff --git a/modules/drivers/sparksql/src/metabase/driver/hive_like.clj b/modules/drivers/sparksql/src/metabase/driver/hive_like.clj index 603638ce23c..b75aac846f0 100644 --- a/modules/drivers/sparksql/src/metabase/driver/hive_like.clj +++ b/modules/drivers/sparksql/src/metabase/driver/hive_like.clj @@ -1,21 +1,22 @@ (ns metabase.driver.hive-like - (:require [buddy.core.codecs :as codecs] - [clojure.string :as str] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [java-time :as t] - [metabase.driver :as driver] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.sql.util :as sql.u] - [metabase.driver.sql.util.unprepare :as unprepare] - [metabase.util.date-2 :as u.date] - [metabase.util.honeysql-extensions :as hx]) - (:import [java.sql ResultSet Types] - [java.time LocalDate OffsetDateTime ZonedDateTime])) + (:require + [buddy.core.codecs :as codecs] + [clojure.string :as str] + [honeysql.format :as hformat] + [java-time :as t] + [metabase.driver :as driver] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.sql.util :as sql.u] + [metabase.driver.sql.util.unprepare :as unprepare] + [metabase.util.date-2 :as u.date] + [metabase.util.honeysql-extensions :as hx]) + (:import + (java.sql ResultSet Types) + (java.time LocalDate OffsetDateTime ZonedDateTime))) (driver/register! :hive-like :parent #{:sql-jdbc ::sql-jdbc.legacy/use-legacy-classes-for-read-and-set} @@ -76,32 +77,32 @@ (defmethod sql.qp/unix-timestamp->honeysql [:hive-like :seconds] [_ _ expr] - (hx/->timestamp (hsql/call :from_unixtime expr))) + (hx/->timestamp (hx/call :from_unixtime expr))) (defn- date-format [format-str expr] - (hsql/call :date_format expr (hx/literal format-str))) + (hx/call :date_format expr (hx/literal format-str))) (defn- str-to-date [format-str expr] (hx/->timestamp - (hsql/call :from_unixtime - (hsql/call :unix_timestamp - expr (hx/literal format-str))))) + (hx/call :from_unixtime + (hx/call :unix_timestamp + expr (hx/literal format-str))))) (defn- trunc-with-format [format-str expr] (str-to-date format-str (date-format format-str expr))) (defmethod sql.qp/date [:hive-like :default] [_ _ expr] (hx/->timestamp expr)) (defmethod sql.qp/date [:hive-like :minute] [_ _ expr] (trunc-with-format "yyyy-MM-dd HH:mm" (hx/->timestamp expr))) -(defmethod sql.qp/date [:hive-like :minute-of-hour] [_ _ expr] (hsql/call :minute (hx/->timestamp expr))) +(defmethod sql.qp/date [:hive-like :minute-of-hour] [_ _ expr] (hx/call :minute (hx/->timestamp expr))) (defmethod sql.qp/date [:hive-like :hour] [_ _ expr] (trunc-with-format "yyyy-MM-dd HH" (hx/->timestamp expr))) -(defmethod sql.qp/date [:hive-like :hour-of-day] [_ _ expr] (hsql/call :hour (hx/->timestamp expr))) +(defmethod sql.qp/date [:hive-like :hour-of-day] [_ _ expr] (hx/call :hour (hx/->timestamp expr))) (defmethod sql.qp/date [:hive-like :day] [_ _ expr] (trunc-with-format "yyyy-MM-dd" (hx/->timestamp expr))) -(defmethod sql.qp/date [:hive-like :day-of-month] [_ _ expr] (hsql/call :dayofmonth (hx/->timestamp expr))) +(defmethod sql.qp/date [:hive-like :day-of-month] [_ _ expr] (hx/call :dayofmonth (hx/->timestamp expr))) (defmethod sql.qp/date [:hive-like :day-of-year] [_ _ expr] (hx/->integer (date-format "D" (hx/->timestamp expr)))) -(defmethod sql.qp/date [:hive-like :month] [_ _ expr] (hsql/call :trunc (hx/->timestamp expr) (hx/literal :MM))) -(defmethod sql.qp/date [:hive-like :month-of-year] [_ _ expr] (hsql/call :month (hx/->timestamp expr))) -(defmethod sql.qp/date [:hive-like :quarter-of-year] [_ _ expr] (hsql/call :quarter (hx/->timestamp expr))) -(defmethod sql.qp/date [:hive-like :year] [_ _ expr] (hsql/call :trunc (hx/->timestamp expr) (hx/literal :year))) +(defmethod sql.qp/date [:hive-like :month] [_ _ expr] (hx/call :trunc (hx/->timestamp expr) (hx/literal :MM))) +(defmethod sql.qp/date [:hive-like :month-of-year] [_ _ expr] (hx/call :month (hx/->timestamp expr))) +(defmethod sql.qp/date [:hive-like :quarter-of-year] [_ _ expr] (hx/call :quarter (hx/->timestamp expr))) +(defmethod sql.qp/date [:hive-like :year] [_ _ expr] (hx/call :trunc (hx/->timestamp expr) (hx/literal :year))) (defrecord DateExtract [unit expr] hformat/ToSql @@ -116,80 +117,80 @@ (defmethod sql.qp/date [:hive-like :week] [driver _ expr] (let [week-extract-fn (fn [expr] - (-> (hsql/call :date_sub - (hx/+ (hx/->timestamp expr) - (hsql/raw "interval '1' day")) - (->DateExtract :dow (hx/->timestamp expr))) + (-> (hx/call :date_sub + (hx/+ (hx/->timestamp expr) + (hx/raw "interval '1' day")) + (->DateExtract :dow (hx/->timestamp expr))) (hx/with-database-type-info "timestamp")))] (sql.qp/adjust-start-of-week driver week-extract-fn expr))) -(defmethod sql.qp/date [:hive-like :week-of-year-iso] [_driver _ expr] (hsql/call :weekofyear (hx/->timestamp expr))) +(defmethod sql.qp/date [:hive-like :week-of-year-iso] [_driver _ expr] (hx/call :weekofyear (hx/->timestamp expr))) (defmethod sql.qp/date [:hive-like :quarter] [_ _ expr] - (hsql/call :add_months - (hsql/call :trunc (hx/->timestamp expr) (hx/literal :year)) - (hx/* (hx/- (hsql/call :quarter (hx/->timestamp expr)) - 1) - 3))) + (hx/call :add_months + (hx/call :trunc (hx/->timestamp expr) (hx/literal :year)) + (hx/* (hx/- (hx/call :quarter (hx/->timestamp expr)) + 1) + 3))) (defmethod sql.qp/->honeysql [:hive-like :replace] [driver [_ arg pattern replacement]] - (hsql/call :regexp_replace - (sql.qp/->honeysql driver arg) - (sql.qp/->honeysql driver pattern) - (sql.qp/->honeysql driver replacement))) + (hx/call :regexp_replace + (sql.qp/->honeysql driver arg) + (sql.qp/->honeysql driver pattern) + (sql.qp/->honeysql driver replacement))) (defmethod sql.qp/->honeysql [:hive-like :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_extract (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern) 0)) + (hx/call :regexp_extract (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern) 0)) (defmethod sql.qp/->honeysql [:hive-like :median] [driver [_ arg]] - (hsql/call :percentile (sql.qp/->honeysql driver arg) 0.5)) + (hx/call :percentile (sql.qp/->honeysql driver arg) 0.5)) (defmethod sql.qp/->honeysql [:hive-like :percentile] [driver [_ arg p]] - (hsql/call :percentile (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver p))) + (hx/call :percentile (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver p))) (defmethod sql.qp/add-interval-honeysql-form :hive-like [driver hsql-form amount unit] (if (= unit :quarter) (recur driver hsql-form (* amount 3) :month) - (hx/+ (hx/->timestamp hsql-form) (hsql/raw (format "(INTERVAL '%d' %s)" (int amount) (name unit)))))) + (hx/+ (hx/->timestamp hsql-form) (hx/raw (format "(INTERVAL '%d' %s)" (int amount) (name unit)))))) (defmethod sql.qp/datetime-diff [:hive-like :year] [driver _unit x y] - (hsql/call :div (sql.qp/datetime-diff driver :month x y) 12)) + (hx/call :div (sql.qp/datetime-diff driver :month x y) 12)) (defmethod sql.qp/datetime-diff [:hive-like :quarter] [driver _unit x y] - (hsql/call :div (sql.qp/datetime-diff driver :month x y) 3)) + (hx/call :div (sql.qp/datetime-diff driver :month x y) 3)) (defmethod sql.qp/datetime-diff [:hive-like :month] [_driver _unit x y] - (hx/->integer (hsql/call :months_between y x))) + (hx/->integer (hx/call :months_between y x))) (defmethod sql.qp/datetime-diff [:hive-like :week] [_driver _unit x y] - (hsql/call :div (hsql/call :datediff y x) 7)) + (hx/call :div (hx/call :datediff y x) 7)) (defmethod sql.qp/datetime-diff [:hive-like :day] [_driver _unit x y] - (hsql/call :datediff y x)) + (hx/call :datediff y x)) (defmethod sql.qp/datetime-diff [:hive-like :hour] [driver _unit x y] - (hsql/call :div (sql.qp/datetime-diff driver :second x y) 3600)) + (hx/call :div (sql.qp/datetime-diff driver :second x y) 3600)) (defmethod sql.qp/datetime-diff [:hive-like :minute] [driver _unit x y] - (hsql/call :div (sql.qp/datetime-diff driver :second x y) 60)) + (hx/call :div (sql.qp/datetime-diff driver :second x y) 60)) (defmethod sql.qp/datetime-diff [:hive-like :second] [_driver _unit x y] - (hsql/call :- (hsql/call :unix_timestamp y) (hsql/call :unix_timestamp x))) + (hx/call :- (hx/call :unix_timestamp y) (hx/call :unix_timestamp x))) (def ^:dynamic *param-splice-style* "How we should splice params into SQL (i.e. 'unprepare' the SQL). Either `:friendly` (the default) or `:paranoid`. diff --git a/modules/drivers/sparksql/src/metabase/driver/sparksql.clj b/modules/drivers/sparksql/src/metabase/driver/sparksql.clj index c6de6899576..d9203dd15ed 100644 --- a/modules/drivers/sparksql/src/metabase/driver/sparksql.clj +++ b/modules/drivers/sparksql/src/metabase/driver/sparksql.clj @@ -1,26 +1,30 @@ (ns metabase.driver.sparksql - (:require [clojure.java.jdbc :as jdbc] - [clojure.string :as str] - [honeysql.core :as hsql] - [honeysql.helpers :as hh] - [medley.core :as m] - [metabase.connection-pool :as connection-pool] - [metabase.driver :as driver] - [metabase.driver.hive-like :as hive-like] - [metabase.driver.hive-like.fixed-hive-connection :as fixed-hive-connection] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.parameters.substitution :as sql.params.substitution] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.sql.util :as sql.u] - [metabase.driver.sql.util.unprepare :as unprepare] - [metabase.mbql.util :as mbql.u] - [metabase.query-processor.store :as qp.store] - [metabase.query-processor.util :as qp.util] - [metabase.query-processor.util.add-alias-info :as add] - [metabase.util.honeysql-extensions :as hx]) - (:import [java.sql Connection ResultSet])) + (:require + [clojure.java.jdbc :as jdbc] + [clojure.string :as str] + [honeysql.core :as hsql] + [honeysql.helpers :as hh] + [medley.core :as m] + [metabase.connection-pool :as connection-pool] + [metabase.driver :as driver] + [metabase.driver.hive-like :as hive-like] + [metabase.driver.hive-like.fixed-hive-connection + :as fixed-hive-connection] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.parameters.substitution + :as sql.params.substitution] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.sql.util :as sql.u] + [metabase.driver.sql.util.unprepare :as unprepare] + [metabase.mbql.util :as mbql.u] + [metabase.query-processor.store :as qp.store] + [metabase.query-processor.util :as qp.util] + [metabase.query-processor.util.add-alias-info :as add] + [metabase.util.honeysql-extensions :as hx]) + (:import + (java.sql Connection ResultSet))) (driver/register! :sparksql, :parent :hive-like) @@ -63,7 +67,7 @@ :allow-dashed-names? true :quoting :mysql)))] (-> (apply hh/select (map last (:select honeysql-form))) - (hh/from (hh/merge-select honeysql-form [(hsql/raw over-clause) :__rownum__])) + (hh/from (hh/merge-select honeysql-form [(hx/raw over-clause) :__rownum__])) (hh/where [:> :__rownum__ offset]) (hh/limit items)))))) diff --git a/modules/drivers/sqlite/src/metabase/driver/sqlite.clj b/modules/drivers/sqlite/src/metabase/driver/sqlite.clj index 949d4bf7d2e..f1623f88557 100644 --- a/modules/drivers/sqlite/src/metabase/driver/sqlite.clj +++ b/modules/drivers/sqlite/src/metabase/driver/sqlite.clj @@ -1,26 +1,28 @@ (ns metabase.driver.sqlite - (:require [clojure.java.io :as io] - [clojure.string :as str] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [java-time :as t] - [metabase.config :as config] - [metabase.driver :as driver] - [metabase.driver.common :as driver.common] - [metabase.driver.sql :as driver.sql] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.parameters.substitution :as sql.params.substitution] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.query-processor.error-type :as qp.error-type] - [metabase.util.date-2 :as u.date] - [metabase.util.honeysql-extensions :as hx] - [metabase.util.i18n :refer [tru]] - [schema.core :as s]) - (:import [java.sql Connection ResultSet Types] - [java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime] - java.time.temporal.Temporal)) + (:require + [clojure.java.io :as io] + [clojure.string :as str] + [honeysql.format :as hformat] + [java-time :as t] + [metabase.config :as config] + [metabase.driver :as driver] + [metabase.driver.common :as driver.common] + [metabase.driver.sql :as driver.sql] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.parameters.substitution + :as sql.params.substitution] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.query-processor.error-type :as qp.error-type] + [metabase.util.date-2 :as u.date] + [metabase.util.honeysql-extensions :as hx] + [metabase.util.i18n :refer [tru]] + [schema.core :as s]) + (:import + (java.sql Connection ResultSet Types) + (java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime) + (java.time.temporal Temporal))) (driver/register! :sqlite, :parent :sql-jdbc) @@ -110,17 +112,17 @@ ;; register the SQLite concatenation operator `||` with HoneySQL as `sqlite-concat` ;; -;; (hsql/format (hsql/call :sqlite-concat :a :b)) -> "(a || b)" +;; (hsql/format (hx/call :sqlite-concat :a :b)) -> "(a || b)" (defmethod hformat/fn-handler "sqlite-concat" [_ & args] (str "(" (str/join " || " (map hformat/to-sql args)) ")")) -(def ^:private ->date (partial hsql/call :date)) -(def ^:private ->datetime (partial hsql/call :datetime)) -(def ^:private ->time (partial hsql/call :time)) +(def ^:private ->date (partial hx/call :date)) +(def ^:private ->datetime (partial hx/call :datetime)) +(def ^:private ->time (partial hx/call :time)) (defn- strftime [format-str expr] - (hsql/call :strftime (hx/literal format-str) expr)) + (hx/call :strftime (hx/literal format-str) expr)) ;; See also the [SQLite Date and Time Functions Reference](http://www.sqlite.org/lang_datefunc.html). @@ -203,11 +205,11 @@ (let [v (sql.qp/->honeysql driver expr)] (->date (->date v (hx/literal "start of month")) - (hsql/call :sqlite-concat - (hx/literal "-") - (hx/mod (hx/dec (strftime "%m" v)) - 3) - (hx/literal " months"))))) + (hx/call :sqlite-concat + (hx/literal "-") + (hx/mod (hx/dec (strftime "%m" v)) + 3) + (hx/literal " months"))))) ;; q = (m + 2) / 3 (defmethod sql.qp/date [:sqlite :quarter-of-year] @@ -276,26 +278,26 @@ (defmethod sql.qp/->honeysql [:sqlite :substring] [driver [_ arg start length]] (if length - (hsql/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)) - (hsql/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start)))) + (hx/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)) + (hx/call :substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start)))) (defmethod sql.qp/->honeysql [:sqlite :concat] [driver [_ & args]] (apply - hsql/call :sqlite-concat + hx/call :sqlite-concat (mapv (partial sql.qp/->honeysql driver) args))) (defmethod sql.qp/->honeysql [:sqlite :floor] [_driver [_ arg]] - (hsql/call :round (hsql/call :- arg 0.5))) + (hx/call :round (hx/call :- arg 0.5))) (defmethod sql.qp/->honeysql [:sqlite :ceil] [_driver [_ arg]] - (hsql/call :case - ;; if we're ceiling a whole number, just cast it to an integer - ;; [:ceil 1.0] should returns 1 - (hsql/call := (hsql/call :round arg) arg) (hx/->integer arg) - :else (hsql/call :round (hsql/call :+ arg 0.5)))) + (hx/call :case + ;; if we're ceiling a whole number, just cast it to an integer + ;; [:ceil 1.0] should returns 1 + (hx/call := (hx/call :round arg) arg) (hx/->integer arg) + :else (hx/call :round (hx/call :+ arg 0.5)))) ;; See https://sqlite.org/lang_datefunc.html @@ -310,33 +312,33 @@ (defmethod sql.qp/->honeysql [:sqlite LocalDate] [_ t] - (hsql/call :date (hx/literal (u.date/format-sql t)))) + (hx/call :date (hx/literal (u.date/format-sql t)))) (defmethod sql.qp/->honeysql [:sqlite LocalDateTime] [driver t] (if (zero-time? t) (sql.qp/->honeysql driver (t/local-date t)) - (hsql/call :datetime (hx/literal (u.date/format-sql t))))) + (hx/call :datetime (hx/literal (u.date/format-sql t))))) (defmethod sql.qp/->honeysql [:sqlite LocalTime] [_ t] - (hsql/call :time (hx/literal (u.date/format-sql t)))) + (hx/call :time (hx/literal (u.date/format-sql t)))) (defmethod sql.qp/->honeysql [:sqlite OffsetDateTime] [driver t] (if (zero-time? t) (sql.qp/->honeysql driver (t/local-date t)) - (hsql/call :datetime (hx/literal (u.date/format-sql t))))) + (hx/call :datetime (hx/literal (u.date/format-sql t))))) (defmethod sql.qp/->honeysql [:sqlite OffsetTime] [_ t] - (hsql/call :time (hx/literal (u.date/format-sql t)))) + (hx/call :time (hx/literal (u.date/format-sql t)))) (defmethod sql.qp/->honeysql [:sqlite ZonedDateTime] [driver t] (if (zero-time? t) (sql.qp/->honeysql driver (t/local-date t)) - (hsql/call :datetime (hx/literal (u.date/format-sql t))))) + (hx/call :datetime (hx/literal (u.date/format-sql t))))) ;; SQLite defaults everything to UTC (defmethod driver.common/current-db-time-date-formatters :sqlite @@ -357,7 +359,7 @@ (defmethod sql.qp/current-datetime-honeysql-form :sqlite [_] - (hsql/call :datetime (hx/literal :now))) + (hx/call :datetime (hx/literal :now))) (defmethod sql.qp/datetime-diff [:sqlite :year] [driver _unit x y] @@ -377,11 +379,11 @@ ;; total-month-diff counts month boundaries not whole months, so we need to adjust ;; if x<y but x>y in the month calendar then subtract one month ;; if x>y but x<y in the month calendar then add one month - (hsql/call + (hx/call :case - (hsql/call :and (hsql/call :< x y) (hsql/call :> (extract :day-of-month x) (extract :day-of-month y))) + (hx/call :and (hx/call :< x y) (hx/call :> (extract :day-of-month x) (extract :day-of-month y))) -1 - (hsql/call :and (hsql/call :> x y) (hsql/call :< (extract :day-of-month x) (extract :day-of-month y))) + (hx/call :and (hx/call :> x y) (hx/call :< (extract :day-of-month x) (extract :day-of-month y))) 1 :else 0)))) @@ -392,8 +394,8 @@ (defmethod sql.qp/datetime-diff [:sqlite :day] [_driver _unit x y] (hx/->integer - (hx/- (hsql/call :julianday y (hx/literal "start of day")) - (hsql/call :julianday x (hx/literal "start of day"))))) + (hx/- (hx/call :julianday y (hx/literal "start of day")) + (hx/call :julianday x (hx/literal "start of day"))))) (defmethod sql.qp/datetime-diff [:sqlite :hour] [driver _unit x y] diff --git a/modules/drivers/sqlserver/src/metabase/driver/sqlserver.clj b/modules/drivers/sqlserver/src/metabase/driver/sqlserver.clj index 87473e1f5c3..d6345e2f43e 100644 --- a/modules/drivers/sqlserver/src/metabase/driver/sqlserver.clj +++ b/modules/drivers/sqlserver/src/metabase/driver/sqlserver.clj @@ -1,30 +1,31 @@ (ns metabase.driver.sqlserver "Driver for SQLServer databases. Uses the official Microsoft JDBC driver under the hood (pre-0.25.0, used jTDS)." - (:require [clojure.data.xml :as xml] - [clojure.java.io :as io] - [clojure.string :as str] - [clojure.tools.logging :as log] - [honeysql.core :as hsql] - [honeysql.helpers :as hh] - [java-time :as t] - [metabase.config :as config] - [metabase.driver :as driver] - [metabase.driver.common :as driver.common] - [metabase.driver.sql :as driver.sql] - [metabase.driver.sql-jdbc.common :as sql-jdbc.common] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.sql.util :as sql.u] - [metabase.driver.sql.util.unprepare :as unprepare] - [metabase.mbql.util :as mbql.u] - [metabase.query-processor.interface :as qp.i] - [metabase.query-processor.timezone :as qp.timezone] - [metabase.util.honeysql-extensions :as hx] - [metabase.util.i18n :refer [trs]]) - (:import [java.sql Connection ResultSet Time] - [java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime])) + (:require + [clojure.data.xml :as xml] + [clojure.java.io :as io] + [clojure.string :as str] + [clojure.tools.logging :as log] + [honeysql.helpers :as hh] + [java-time :as t] + [metabase.config :as config] + [metabase.driver :as driver] + [metabase.driver.common :as driver.common] + [metabase.driver.sql :as driver.sql] + [metabase.driver.sql-jdbc.common :as sql-jdbc.common] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.sql.util :as sql.u] + [metabase.driver.sql.util.unprepare :as unprepare] + [metabase.mbql.util :as mbql.u] + [metabase.query-processor.interface :as qp.i] + [metabase.query-processor.timezone :as qp.timezone] + [metabase.util.honeysql-extensions :as hx] + [metabase.util.i18n :refer [trs]]) + (:import + (java.sql Connection ResultSet Time) + (java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime))) (driver/register! :sqlserver, :parent :sql-jdbc) @@ -130,13 +131,13 @@ ;; See https://docs.microsoft.com/en-us/sql/t-sql/functions/datepart-transact-sql?view=sql-server-ver15 (defn- date-part [unit expr] - (hsql/call :datepart (hsql/raw (name unit)) expr)) + (hx/call :datepart (hx/raw (name unit)) expr)) (defn- date-add [unit & exprs] - (apply hsql/call :dateadd (hsql/raw (name unit)) exprs)) + (apply hx/call :dateadd (hx/raw (name unit)) exprs)) (defn- date-diff [unit x y] - (hsql/call :datediff_big (hsql/raw (name unit)) x y)) + (hx/call :datediff_big (hx/raw (name unit)) x y)) ;; See https://docs.microsoft.com/en-us/sql/t-sql/functions/date-and-time-data-types-and-functions-transact-sql for ;; details on the functions we're using. @@ -159,7 +160,7 @@ (defmethod sql.qp/date [:sqlserver :hour] [_ _ expr] - (hsql/call :datetime2fromparts (hx/year expr) (hx/month expr) (hx/day expr) (date-part :hour expr) 0 0 0 0)) + (hx/call :datetime2fromparts (hx/year expr) (hx/month expr) (hx/day expr) (date-part :hour expr) 0 0 0 0)) (defmethod sql.qp/date [:sqlserver :hour-of-day] [_ _ expr] @@ -171,7 +172,7 @@ ;; SQL functions like `day()` that don't return a full DATE. See `optimized-temporal-buckets` below for more info. (if (::optimized-bucketing? *field-options*) (hx/day expr) - (hsql/call :DateFromParts (hx/year expr) (hx/month expr) (hx/day expr)))) + (hx/call :DateFromParts (hx/year expr) (hx/month expr) (hx/day expr)))) (defmethod sql.qp/date [:sqlserver :day-of-week] [_ _ expr] @@ -208,7 +209,7 @@ [_ _ expr] (if (::optimized-bucketing? *field-options*) (hx/month expr) - (hsql/call :DateFromParts (hx/year expr) (hx/month expr) 1))) + (hx/call :DateFromParts (hx/year expr) (hx/month expr) 1))) (defmethod sql.qp/date [:sqlserver :month-of-year] [_ _ expr] @@ -221,7 +222,7 @@ [_ _ expr] (date-add :quarter (hx/dec (date-part :quarter expr)) - (hsql/call :DateFromParts (hx/year expr) 1 1))) + (hx/call :DateFromParts (hx/year expr) 1 1))) (defmethod sql.qp/date [:sqlserver :quarter-of-year] [_ _ expr] @@ -231,7 +232,7 @@ [_ _ expr] (if (::optimized-bucketing? *field-options*) (hx/year expr) - (hsql/call :DateFromParts (hx/year expr) 1 1))) + (hx/call :DateFromParts (hx/year expr) 1 1))) (defmethod sql.qp/date [:sqlserver :year-of-era] [_ _ expr] @@ -308,10 +309,10 @@ ;; datediff counts month boundaries not whole months, so we need to adjust ;; if x<y but x>y in the month calendar then subtract one month ;; if x>y but x<y in the month calendar then add one month - (hsql/call + (hx/call :case - (hsql/call :and (hsql/call :< x y) (hsql/call :> (date-part :day x) (date-part :day y))) -1 - (hsql/call :and (hsql/call :> x y) (hsql/call :< (date-part :day x) (date-part :day y))) 1 + (hx/call :and (hx/call :< x y) (hx/call :> (date-part :day x) (date-part :day y))) -1 + (hx/call :and (hx/call :> x y) (hx/call :< (date-part :day x) (date-part :day y))) 1 :else 0))) (defmethod sql.qp/datetime-diff [:sqlserver :week] [_driver _unit x y] (hx// (date-diff :day x y) 7)) @@ -329,7 +330,7 @@ ;; "20190421164300" -> "2019-04-21 16:43:00" ;; 5 8 11 14 17 (let [formatted (reduce (fn [expr [index c]] - (hsql/call :stuff expr index 0 c)) + (hx/call :stuff expr index 0 c)) expr [[5 "-"] [8 "-"] @@ -339,7 +340,7 @@ ;; 20 is ODBC canonical yyyy-mm-dd hh:mi:ss (24h). I couldn't find a way to use an arbitrary format string when ;; parsing and SO seems to push towards manually formatting a string and then parsing with one of the available ;; formats. Not great. - (hsql/call :convert (hsql/raw "datetime2") formatted 20))) + (hx/call :convert (hx/raw "datetime2") formatted 20))) (defmethod sql.qp/apply-top-level-clause [:sqlserver :limit] [_ _ honeysql-form {value :limit}] @@ -347,9 +348,9 @@ (defmethod sql.qp/apply-top-level-clause [:sqlserver :page] [_ _ honeysql-form {{:keys [items page]} :page}] - (assoc honeysql-form :offset (hsql/raw (format "%d ROWS FETCH NEXT %d ROWS ONLY" - (* items (dec page)) - items)))) + (assoc honeysql-form :offset (hx/raw (format "%d ROWS FETCH NEXT %d ROWS ONLY" + (* items (dec page)) + items)))) (defn- optimized-temporal-buckets "If `field-clause` is being truncated temporally to `:year`, `:month`, or `:day`, return a optimized set of @@ -448,33 +449,33 @@ (defmethod sql.qp/->honeysql [:sqlserver :stddev] [driver [_ field]] - (hsql/call :stdevp (sql.qp/->honeysql driver field))) + (hx/call :stdevp (sql.qp/->honeysql driver field))) (defmethod sql.qp/->honeysql [:sqlserver :var] [driver [_ field]] - (hsql/call :varp (sql.qp/->honeysql driver field))) + (hx/call :varp (sql.qp/->honeysql driver field))) (defmethod sql.qp/->honeysql [:sqlserver :substring] [driver [_ arg start length]] (if length - (hsql/call :substring (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)) - (hsql/call :substring (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (hsql/call :len (sql.qp/->honeysql driver arg))))) + (hx/call :substring (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (sql.qp/->honeysql driver length)) + (hx/call :substring (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver start) (hx/call :len (sql.qp/->honeysql driver arg))))) (defmethod sql.qp/->honeysql [:sqlserver :length] [driver [_ arg]] - (hsql/call :len (sql.qp/->honeysql driver arg))) + (hx/call :len (sql.qp/->honeysql driver arg))) (defmethod sql.qp/->honeysql [:sqlserver :ceil] [driver [_ arg]] - (hsql/call :ceiling (sql.qp/->honeysql driver arg))) + (hx/call :ceiling (sql.qp/->honeysql driver arg))) (defmethod sql.qp/->honeysql [:sqlserver :round] [driver [_ arg]] - (hsql/call :round (hx/cast :float (sql.qp/->honeysql driver arg)) 0)) + (hx/call :round (hx/cast :float (sql.qp/->honeysql driver arg)) 0)) (defmethod sql.qp/->honeysql [:sqlserver :power] [driver [_ arg power]] - (hsql/call :power (hx/cast :float (sql.qp/->honeysql driver arg)) (sql.qp/->honeysql driver power))) + (hx/call :power (hx/cast :float (sql.qp/->honeysql driver arg)) (sql.qp/->honeysql driver power))) (defmethod sql.qp/->honeysql [:sqlserver :median] [driver [_ arg]] diff --git a/modules/drivers/vertica/src/metabase/driver/vertica.clj b/modules/drivers/vertica/src/metabase/driver/vertica.clj index 30199603981..73985989348 100644 --- a/modules/drivers/vertica/src/metabase/driver/vertica.clj +++ b/modules/drivers/vertica/src/metabase/driver/vertica.clj @@ -1,25 +1,27 @@ (ns metabase.driver.vertica - (:require [clojure.java.jdbc :as jdbc] - [clojure.set :as set] - [clojure.tools.logging :as log] - [honeysql.core :as hsql] - [honeysql.format :as hformat] - [metabase.driver :as driver] - [metabase.driver.common :as driver.common] - [metabase.driver.sql-jdbc.common :as sql-jdbc.common] - [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] - [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] - [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] - [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] - [metabase.driver.sql.query-processor :as sql.qp] - [metabase.driver.sql.query-processor.empty-string-is-null :as sql.qp.empty-string-is-null] - [metabase.driver.sql.util :as sql.u] - [metabase.query-processor.timezone :as qp.timezone] - [metabase.util :as u] - [metabase.util.date-2 :as u.date] - [metabase.util.honeysql-extensions :as hx] - [metabase.util.i18n :refer [trs]]) - (:import [java.sql ResultSet ResultSetMetaData Types])) + (:require + [clojure.java.jdbc :as jdbc] + [clojure.set :as set] + [clojure.tools.logging :as log] + [honeysql.format :as hformat] + [metabase.driver :as driver] + [metabase.driver.common :as driver.common] + [metabase.driver.sql-jdbc.common :as sql-jdbc.common] + [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn] + [metabase.driver.sql-jdbc.execute :as sql-jdbc.execute] + [metabase.driver.sql-jdbc.execute.legacy-impl :as sql-jdbc.legacy] + [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync] + [metabase.driver.sql.query-processor :as sql.qp] + [metabase.driver.sql.query-processor.empty-string-is-null + :as sql.qp.empty-string-is-null] + [metabase.driver.sql.util :as sql.u] + [metabase.query-processor.timezone :as qp.timezone] + [metabase.util :as u] + [metabase.util.date-2 :as u.date] + [metabase.util.honeysql-extensions :as hx] + [metabase.util.i18n :refer [trs]]) + (:import + (java.sql ResultSet ResultSetMetaData Types))) (driver/register! :vertica, :parent #{:sql-jdbc ::sql-jdbc.legacy/use-legacy-classes-for-read-and-set @@ -77,11 +79,11 @@ (defmethod sql.qp/current-datetime-honeysql-form :vertica [_] - (hx/with-database-type-info (hsql/call :current_timestamp 6) :TimestampTz)) + (hx/with-database-type-info (hx/call :current_timestamp 6) :TimestampTz)) (defmethod sql.qp/unix-timestamp->honeysql [:vertica :seconds] [_ _ expr] - (hsql/call :to_timestamp expr)) + (hx/call :to_timestamp expr)) ;; TODO - not sure if needed or not (defn- cast-timestamp @@ -93,9 +95,9 @@ (hx/cast :timestamp expr) expr)) -(defn- date-trunc [unit expr] (hsql/call :date_trunc (hx/literal unit) (cast-timestamp expr))) -(defn- extract [unit expr] (hsql/call :extract unit (cast-timestamp expr))) -(defn- datediff [unit a b] (hsql/call :datediff (hx/literal unit) (cast-timestamp a) (cast-timestamp b))) +(defn- date-trunc [unit expr] (hx/call :date_trunc (hx/literal unit) (cast-timestamp expr))) +(defn- extract [unit expr] (hx/call :extract unit (cast-timestamp expr))) +(defn- datediff [unit a b] (hx/call :datediff (hx/literal unit) (cast-timestamp a) (cast-timestamp b))) (def ^:private extract-integer (comp hx/->integer extract)) @@ -118,11 +120,11 @@ [_ _ expr] (sql.qp/adjust-start-of-week :vertica (partial date-trunc :week) (cast-timestamp expr))) -(defmethod sql.qp/date [:vertica :week-of-year-iso] [_driver _ expr] (hsql/call :week_iso expr)) +(defmethod sql.qp/date [:vertica :week-of-year-iso] [_driver _ expr] (hx/call :week_iso expr)) (defmethod sql.qp/date [:vertica :day-of-week] [_ _ expr] - (sql.qp/adjust-day-of-week :vertica (hsql/call :dayofweek_iso expr))) + (sql.qp/adjust-day-of-week :vertica (hx/call :dayofweek_iso expr))) (defmethod sql.qp/->honeysql [:vertica :convert-timezone] [driver [_ arg target-timezone source-timezone]] @@ -139,17 +141,17 @@ [driver [_ & args]] (->> args (map (partial sql.qp/->honeysql driver)) - (reduce (partial hsql/call :concat)))) + (reduce (partial hx/call :concat)))) (defmethod sql.qp/datetime-diff [:vertica :year] [driver _unit x y] (let [months (sql.qp/datetime-diff driver :month x y)] - (hx/->integer (hsql/call :trunc (hx// months 12))))) + (hx/->integer (hx/call :trunc (hx// months 12))))) (defmethod sql.qp/datetime-diff [:vertica :quarter] [driver _unit x y] (let [months (sql.qp/datetime-diff driver :month x y)] - (hx/->integer (hsql/call :trunc (hx// months 3))))) + (hx/->integer (hx/call :trunc (hx// months 3))))) (defmethod sql.qp/datetime-diff [:vertica :month] [_driver _unit x y] @@ -157,19 +159,19 @@ ;; datediff counts month boundaries not whole months, so we need to adjust ;; if x<y but x>y in the month calendar then subtract one month ;; if x>y but x<y in the month calendar then add one month - (hsql/call + (hx/call :case - (hsql/call :and - (hsql/call :< (cast-timestamp x) (cast-timestamp y)) - (hsql/call :> (extract :day x) (extract :day y))) -1 - (hsql/call :and - (hsql/call :> (cast-timestamp x) (cast-timestamp y)) - (hsql/call :< (extract :day x) (extract :day y))) 1 + (hx/call :and + (hx/call :< (cast-timestamp x) (cast-timestamp y)) + (hx/call :> (extract :day x) (extract :day y))) -1 + (hx/call :and + (hx/call :> (cast-timestamp x) (cast-timestamp y)) + (hx/call :< (extract :day x) (extract :day y))) 1 :else 0))) (defmethod sql.qp/datetime-diff [:vertica :week] [_driver _unit x y] - (hx/->integer (hsql/call :trunc (hx// (datediff :day x y) 7)))) + (hx/->integer (hx/call :trunc (hx// (datediff :day x y) 7)))) (defmethod sql.qp/datetime-diff [:vertica :day] [_driver _unit x y] @@ -178,44 +180,44 @@ (defmethod sql.qp/datetime-diff [:vertica :hour] [_driver _unit x y] (let [seconds (hx/- (extract :epoch y) (extract :epoch x))] - (hx/->integer (hsql/call :trunc (hx// seconds 3600))))) + (hx/->integer (hx/call :trunc (hx// seconds 3600))))) (defmethod sql.qp/datetime-diff [:vertica :minute] [_driver _unit x y] (let [seconds (hx/- (extract :epoch y) (extract :epoch x))] - (hx/->integer (hsql/call :trunc (hx// seconds 60))))) + (hx/->integer (hx/call :trunc (hx// seconds 60))))) (defmethod sql.qp/datetime-diff [:vertica :second] [_driver _unit x y] - (hx/->integer (hsql/call :trunc (hx/- (extract :epoch y) (extract :epoch x))))) + (hx/->integer (hx/call :trunc (hx/- (extract :epoch y) (extract :epoch x))))) (defmethod sql.qp/->honeysql [:vertica :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (defmethod sql.qp/->honeysql [:vertica :percentile] [driver [_ arg p]] - (hsql/raw (format "APPROXIMATE_PERCENTILE(%s USING PARAMETERS percentile=%s)" - (hformat/to-sql (sql.qp/->honeysql driver arg)) - (hformat/to-sql (sql.qp/->honeysql driver p))))) + (hx/raw (format "APPROXIMATE_PERCENTILE(%s USING PARAMETERS percentile=%s)" + (hformat/to-sql (sql.qp/->honeysql driver arg)) + (hformat/to-sql (sql.qp/->honeysql driver p))))) (defmethod sql.qp/->honeysql [:vertica :median] [driver [_ arg]] - (hsql/call :approximate_median (sql.qp/->honeysql driver arg))) + (hx/call :approximate_median (sql.qp/->honeysql driver arg))) (defmethod sql.qp/add-interval-honeysql-form :vertica [_ hsql-form amount unit] - (hsql/call :timestampadd unit) + (hx/call :timestampadd unit) ;; using `timestampadd` instead of `+ (INTERVAL)` because vertica add inteval for month, or year ;; by adding the equivalent number of days, not adding the unit compoinent. ;; For example `select date '2004-02-02' + interval '1 year' will return `2005-02-01` because it's adding ;; 365 days under the hood and 2004 is a leap year. Whereas other dbs will return `2006-02-02`. ;; So we use timestampadd to make the behavior consistent with other dbs (let [acceptable-types (case unit - (:millisecond :second :minute :hour) #{"time" "timetz" "timestamp" "timestamptz"} - (:day :week :month :quarter :year) #{"date" "timestamp" "timestamptz"}) + (:millisecond :second :minute :hour) #{"time" "timetz" "timestamp" "timestamptz"} + (:day :week :month :quarter :year) #{"date" "timestamp" "timestamptz"}) hsql-form (hx/cast-unless-type-in "timestamp" acceptable-types hsql-form)] - (hsql/call :timestampadd unit amount hsql-form))) + (hx/call :timestampadd unit amount hsql-form))) (defn- materialized-views "Fetch the Materialized Views for a Vertica `database`. diff --git a/src/metabase/driver/h2.clj b/src/metabase/driver/h2.clj index f4ba36fc0da..7a544ee568d 100644 --- a/src/metabase/driver/h2.clj +++ b/src/metabase/driver/h2.clj @@ -3,7 +3,6 @@ [clojure.math.combinatorics :as math.combo] [clojure.string :as str] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [java-time :as t] [metabase.db.jdbc-protocols :as mdb.jdbc-protocols] [metabase.db.spec :as mdb.spec] @@ -50,7 +49,7 @@ (defmethod sql.qp/->honeysql [:h2 :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (defmethod driver/connection-properties :h2 [_] @@ -158,10 +157,7 @@ (recur driver hsql-form (* amount 1000.0) :millisecond) :else - (let [args [:dateadd (hx/literal unit) (hx/cast :long amount) (hx/cast :datetime hsql-form)]] - (case hx/*honey-sql-version* - 1 (apply hsql/call args) - 2 args)))) + (hx/call :dateadd (hx/literal unit) (hx/cast :long amount) (hx/cast :datetime hsql-form)))) (defmethod driver/humanize-connection-error-message :h2 [_ message] @@ -201,10 +197,10 @@ (hx/with-database-type-info :%now :TIMESTAMP)) (defn- add-to-1970 [expr unit-str] - (hsql/call :timestampadd + (hx/call :timestampadd (hx/literal unit-str) expr - (hsql/raw "timestamp '1970-01-01T00:00:00Z'"))) + (hx/raw "timestamp '1970-01-01T00:00:00Z'"))) (defmethod sql.qp/unix-timestamp->honeysql [:h2 :seconds] [_ _ expr] (add-to-1970 expr "second")) @@ -217,16 +213,16 @@ (defmethod sql.qp/cast-temporal-string [:h2 :Coercion/YYYYMMDDHHMMSSString->Temporal] [_driver _coercion-strategy expr] - (hsql/call :parsedatetime expr (hx/literal "yyyyMMddHHmmss"))) + (hx/call :parsedatetime expr (hx/literal "yyyyMMddHHmmss"))) (defmethod sql.qp/cast-temporal-byte [:h2 :Coercion/YYYYMMDDHHMMSSBytes->Temporal] [driver _coercion-strategy expr] (sql.qp/cast-temporal-string driver :Coercion/YYYYMMDDHHMMSSString->Temporal - (hsql/call :utf8tostring expr))) + (hx/call :utf8tostring expr))) ;; H2 v2 added date_trunc and extract, so we can borrow the Postgres implementation -(defn- date-trunc [unit expr] (hsql/call :date_trunc (hx/literal unit) expr)) -(defn- extract [unit expr] (hsql/call :extract unit expr)) +(defn- date-trunc [unit expr] (hx/call :date_trunc (hx/literal unit) expr)) +(defn- extract [unit expr] (hx/call :extract unit expr)) (def ^:private extract-integer (comp hx/->integer extract)) @@ -260,12 +256,12 @@ (defmethod sql.qp/->honeysql [:h2 :log] [driver [_ field]] - (hsql/call :log10 (sql.qp/->honeysql driver field))) + (hx/call :log10 (sql.qp/->honeysql driver field))) (defn- datediff "Like H2's `datediff` function but accounts for timestamps with time zones." [unit x y] - (hsql/call :datediff (hsql/raw (name unit)) (hx/->timestamp x) (hx/->timestamp y))) + (hx/call :datediff (hx/raw (name unit)) (hx/->timestamp x) (hx/->timestamp y))) (defn- time-zoned-extract "Like H2's extract but accounts for timestamps with time zones." @@ -281,11 +277,11 @@ ;; datediff counts month boundaries not whole months, so we need to adjust ;; if x<y but x>y in the month calendar then subtract one month ;; if x>y but x<y in the month calendar then add one month - (hsql/call + (hx/call :case - (hsql/call :and (hsql/call :< x y) (hsql/call :> (time-zoned-extract :day x) (time-zoned-extract :day y))) + (hx/call :and (hx/call :< x y) (hx/call :> (time-zoned-extract :day x) (time-zoned-extract :day y))) -1 - (hsql/call :and (hsql/call :> x y) (hsql/call :< (time-zoned-extract :day x) (time-zoned-extract :day y))) + (hx/call :and (hx/call :> x y) (hx/call :< (time-zoned-extract :day x) (time-zoned-extract :day y))) 1 :else 0))) diff --git a/src/metabase/driver/mysql.clj b/src/metabase/driver/mysql.clj index 11f2284c52d..8860edc0ba7 100644 --- a/src/metabase/driver/mysql.clj +++ b/src/metabase/driver/mysql.clj @@ -6,7 +6,6 @@ [clojure.string :as str] [clojure.tools.logging :as log] [clojure.walk :as walk] - [honeysql.core :as hsql] [honeysql.format :as hformat] [java-time :as t] [metabase.config :as config] @@ -35,6 +34,7 @@ (java.sql DatabaseMetaData ResultSet ResultSetMetaData Types) (java.time LocalDateTime OffsetDateTime OffsetTime ZonedDateTime) (metabase.util.honey_sql_1_extensions Identifier))) + (comment ;; method impls live in these namespaces. mysql.actions/keep-me @@ -149,14 +149,16 @@ ;; MySQL doesn't support `:millisecond` as an option, but does support fractional seconds (if (= unit :millisecond) (recur driver hsql-form (/ amount 1000.0) :second) - (case hx/*honey-sql-version* - 1 (hsql/call :date_add hsql-form (hsql/raw (format "INTERVAL %s %s" amount (name unit)))) - 2 [:date_add hsql-form [:raw (format "INTERVAL %s %s" amount (name unit))]]))) + (hx/call :date_add hsql-form (hx/raw (format "INTERVAL %s %s" amount (name unit)))))) ;; now() returns current timestamp in seconds resolution; now(6) returns it in nanosecond resolution (defmethod sql.qp/current-datetime-honeysql-form :mysql [_] - (hx/with-database-type-info (hsql/call :now 6) "timestamp")) + (hx/with-database-type-info + (case hx/*honey-sql-version* + 1 (hx/call :now 6) + 2 [:now [:inline 6]]) + "timestamp")) (defmethod driver/humanize-connection-error-message :mysql [_ message] @@ -231,7 +233,7 @@ ;;; +----------------------------------------------------------------------------------------------------------------+ (defmethod sql.qp/unix-timestamp->honeysql [:mysql :seconds] [_ _ expr] - (hsql/call :from_unixtime expr)) + (hx/call :from_unixtime expr)) (defmethod sql.qp/cast-temporal-string [:mysql :Coercion/ISO8601->DateTime] [_driver _coercion-strategy expr] @@ -239,14 +241,14 @@ (defmethod sql.qp/cast-temporal-string [:mysql :Coercion/YYYYMMDDHHMMSSString->Temporal] [_driver _coercion-strategy expr] - (hsql/call :convert expr (hsql/raw "DATETIME"))) + (hx/call :convert expr (hx/raw "DATETIME"))) (defmethod sql.qp/cast-temporal-byte [:mysql :Coercion/YYYYMMDDHHMMSSBytes->Temporal] [driver _coercion-strategy expr] (sql.qp/cast-temporal-string driver :Coercion/YYYYMMDDHHMMSSString->Temporal expr)) -(defn- date-format [format-str expr] (hsql/call :date_format expr (hx/literal format-str))) -(defn- str-to-date [format-str expr] (hsql/call :str_to_date expr (hx/literal format-str))) +(defn- date-format [format-str expr] (hx/call :date_format expr (hx/literal format-str))) +(defn- str-to-date [format-str expr] (hx/call :str_to_date expr (hx/literal format-str))) (defmethod sql.qp/->float :mysql [_ value] @@ -259,11 +261,11 @@ (defmethod sql.qp/->honeysql [:mysql :regex-match-first] [driver [_ arg pattern]] - (hsql/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) + (hx/call :regexp_substr (sql.qp/->honeysql driver arg) (sql.qp/->honeysql driver pattern))) (defmethod sql.qp/->honeysql [:mysql :length] [driver [_ arg]] - (hsql/call :char_length (sql.qp/->honeysql driver arg))) + (hx/call :char_length (sql.qp/->honeysql driver arg))) (def ^:private database-type->mysql-cast-type-name "MySQL supports the ordinary SQL standard database type names for actual type stuff but not for coercions, sometimes. @@ -281,17 +283,17 @@ nfc-path (:nfc_path stored-field) parent-identifier (field/nfc-field->parent-identifier unwrapped-identifier stored-field) jsonpath-query (format "$.%s" (str/join "." (map handle-name (rest nfc-path)))) - json-extract+jsonpath (hsql/call :json_extract (hsql/raw (hformat/to-sql parent-identifier)) jsonpath-query)] + json-extract+jsonpath (hx/call :json_extract (hx/raw (hformat/to-sql parent-identifier)) jsonpath-query)] (case field-type ;; If we see JSON datetimes we expect them to be in ISO8601. However, MySQL expects them as something different. ;; We explicitly tell MySQL to go and accept ISO8601, because that is JSON datetimes, although there is no real standard for JSON, ISO8601 is the de facto standard. - "timestamp" (hsql/call :convert - (hsql/call :str_to_date json-extract+jsonpath "\"%Y-%m-%dT%T.%fZ\"") - (hsql/raw "DATETIME")) + "timestamp" (hx/call :convert + (hx/call :str_to_date json-extract+jsonpath "\"%Y-%m-%dT%T.%fZ\"") + (hx/raw "DATETIME")) "boolean" json-extract+jsonpath - (hsql/call :convert json-extract+jsonpath (hsql/raw (u/upper-case-en field-type))))))) + (hx/call :convert json-extract+jsonpath (hx/raw (u/upper-case-en field-type))))))) (defmethod sql.qp/->honeysql [:mysql :field] [driver [_ id-or-name opts :as clause]] @@ -319,13 +321,13 @@ (defn- ->date [expr] (if (hx/is-of-type? expr "date") expr - (-> (hsql/call :date expr) + (-> (hx/call :date expr) (hx/with-database-type-info "date")))) (defn make-date "Create and return a date based on a year and a number of days value." [year-expr number-of-days] - (-> (hsql/call :makedate year-expr number-of-days) + (-> (hx/call :makedate year-expr number-of-days) (hx/with-database-type-info "date"))) (defmethod sql.qp/date [:mysql :default] [_ _ expr] expr) @@ -334,22 +336,22 @@ (defmethod sql.qp/date [:mysql :hour] [_ _ expr] (trunc-with-format "%Y-%m-%d %H" expr)) (defmethod sql.qp/date [:mysql :hour-of-day] [_ _ expr] (hx/hour expr)) (defmethod sql.qp/date [:mysql :day] [_ _ expr] (->date expr)) -(defmethod sql.qp/date [:mysql :day-of-month] [_ _ expr] (hsql/call :dayofmonth expr)) -(defmethod sql.qp/date [:mysql :day-of-year] [_ _ expr] (hsql/call :dayofyear expr)) +(defmethod sql.qp/date [:mysql :day-of-month] [_ _ expr] (hx/call :dayofmonth expr)) +(defmethod sql.qp/date [:mysql :day-of-year] [_ _ expr] (hx/call :dayofyear expr)) (defmethod sql.qp/date [:mysql :month-of-year] [_ _ expr] (hx/month expr)) (defmethod sql.qp/date [:mysql :quarter-of-year] [_ _ expr] (hx/quarter expr)) (defmethod sql.qp/date [:mysql :year] [_ _ expr] (make-date (hx/year expr) 1)) (defmethod sql.qp/date [:mysql :day-of-week] [_ _ expr] - (sql.qp/adjust-day-of-week :mysql (hsql/call :dayofweek expr))) + (sql.qp/adjust-day-of-week :mysql (hx/call :dayofweek expr))) ;; To convert a YEARWEEK (e.g. 201530) back to a date you need tell MySQL which day of the week to use, ;; because otherwise as far as MySQL is concerned you could be talking about any of the days in that week (defmethod sql.qp/date [:mysql :week] [_ _ expr] (let [extract-week-fn (fn [expr] (str-to-date "%X%V %W" - (hx/concat (hsql/call :yearweek expr) + (hx/concat (hx/call :yearweek expr) (hx/literal " Sunday"))))] (sql.qp/adjust-start-of-week :mysql extract-week-fn expr))) @@ -377,20 +379,20 @@ timestamp? (hx/is-of-type? expr "timestamp")] (sql.u/validate-convert-timezone-args timestamp? target-timezone source-timezone) (hx/with-database-type-info - (hsql/call :convert_tz expr (or source-timezone (qp.timezone/results-timezone-id)) target-timezone) + (hx/call :convert_tz expr (or source-timezone (qp.timezone/results-timezone-id)) target-timezone) "datetime"))) (defn- timestampdiff-dates [unit x y] - (hsql/call :timestampdiff (hsql/raw (name unit)) (hx/->date x) (hx/->date y))) + (hx/call :timestampdiff (hx/raw (name unit)) (hx/->date x) (hx/->date y))) (defn- timestampdiff [unit x y] - (hsql/call :timestampdiff (hsql/raw (name unit)) x y)) + (hx/call :timestampdiff (hx/raw (name unit)) x y)) (defmethod sql.qp/datetime-diff [:mysql :year] [_driver _unit x y] (timestampdiff-dates :year x y)) (defmethod sql.qp/datetime-diff [:mysql :quarter] [_driver _unit x y] (timestampdiff-dates :quarter x y)) (defmethod sql.qp/datetime-diff [:mysql :month] [_driver _unit x y] (timestampdiff-dates :month x y)) (defmethod sql.qp/datetime-diff [:mysql :week] [_driver _unit x y] (timestampdiff-dates :week x y)) -(defmethod sql.qp/datetime-diff [:mysql :day] [_driver _unit x y] (hsql/call :datediff y x)) +(defmethod sql.qp/datetime-diff [:mysql :day] [_driver _unit x y] (hx/call :datediff y x)) (defmethod sql.qp/datetime-diff [:mysql :hour] [_driver _unit x y] (timestampdiff :hour x y)) (defmethod sql.qp/datetime-diff [:mysql :minute] [_driver _unit x y] (timestampdiff :minute x y)) (defmethod sql.qp/datetime-diff [:mysql :second] [_driver _unit x y] (timestampdiff :second x y)) diff --git a/src/metabase/driver/postgres.clj b/src/metabase/driver/postgres.clj index d2ff9e8567a..88e3792fe97 100644 --- a/src/metabase/driver/postgres.clj +++ b/src/metabase/driver/postgres.clj @@ -7,7 +7,6 @@ [clojure.string :as str] [clojure.tools.logging :as log] [clojure.walk :as walk] - [honeysql.core :as hsql] [honeysql.format :as hformat] [java-time :as t] [metabase.db.spec :as mdb.spec] @@ -96,9 +95,7 @@ (recur driver hsql-form (* 3 amount) :month) (let [hsql-form (->timestamp hsql-form)] (-> (hx/+ hsql-form (let [s (format "(INTERVAL '%s %s')" amount (name unit))] - (case hx/*honey-sql-version* - 1 (hsql/raw s) - 2 [:raw s]))) + (hx/raw s))) (hx/with-type-info (hx/type-info hsql-form)))))) (defmethod driver/humanize-connection-error-message :postgres @@ -248,19 +245,19 @@ (defmethod sql.qp/unix-timestamp->honeysql [:postgres :seconds] [_ _ expr] - (hsql/call :to_timestamp expr)) + (hx/call :to_timestamp expr)) (defmethod sql.qp/cast-temporal-string [:postgres :Coercion/YYYYMMDDHHMMSSString->Temporal] [_driver _coercion-strategy expr] - (hsql/call :to_timestamp expr (hx/literal "YYYYMMDDHH24MISS"))) + (hx/call :to_timestamp expr (hx/literal "YYYYMMDDHH24MISS"))) (defmethod sql.qp/cast-temporal-byte [:postgres :Coercion/YYYYMMDDHHMMSSBytes->Temporal] [driver _coercion-strategy expr] (sql.qp/cast-temporal-string driver :Coercion/YYYYMMDDHHMMSSString->Temporal - (hsql/call :convert_from expr (hx/literal "UTF8")))) + (hx/call :convert_from expr (hx/literal "UTF8")))) -(defn- date-trunc [unit expr] (hsql/call :date_trunc (hx/literal unit) (->timestamp expr))) -(defn- extract [unit expr] (hsql/call :extract unit (->timestamp expr))) +(defn- date-trunc [unit expr] (hx/call :date_trunc (hx/literal unit) (->timestamp expr))) +(defn- extract [unit expr] (hx/call :extract unit (->timestamp expr))) (def ^:private extract-integer (comp hx/->integer extract)) @@ -308,9 +305,9 @@ _ (sql.u/validate-convert-timezone-args timestamptz? target-timezone source-timezone) expr (cond->> expr (not timestamptz?) - (hsql/call :timezone source-timezone) + (hx/call :timezone source-timezone) :always - (hsql/call :timezone target-timezone))] + (hx/call :timezone target-timezone))] (hx/with-database-type-info expr "timestamp"))) (defmethod sql.qp/->honeysql [:postgres :value] @@ -332,8 +329,8 @@ (defmethod sql.qp/datetime-diff [:postgres :year] [_driver _unit x y] - (let [interval (hsql/call :age (date-trunc :day y) (date-trunc :day x))] - (hx/->integer (hsql/call :extract :year interval)))) + (let [interval (hx/call :age (date-trunc :day y) (date-trunc :day x))] + (hx/->integer (hx/call :extract :year interval)))) (defmethod sql.qp/datetime-diff [:postgres :quarter] [driver _unit x y] @@ -341,9 +338,9 @@ (defmethod sql.qp/datetime-diff [:postgres :month] [_driver _unit x y] - (let [interval (hsql/call :age (date-trunc :day y) (date-trunc :day x)) - year-diff (hsql/call :extract :year interval) - month-of-year-diff (hsql/call :extract :month interval)] + (let [interval (hx/call :age (date-trunc :day y) (date-trunc :day x)) + year-diff (hx/call :extract :year interval) + month-of-year-diff (hx/call :extract :month interval)] (hx/->integer (hx/+ month-of-year-diff (hx/* year-diff 12))))) (defmethod sql.qp/datetime-diff [:postgres :week] @@ -353,7 +350,7 @@ (defmethod sql.qp/datetime-diff [:postgres :day] [_driver _unit x y] (let [interval (hx/- (date-trunc :day y) (date-trunc :day x))] - (hx/->integer (hsql/call :extract :day interval)))) + (hx/->integer (hx/call :extract :day interval)))) (defmethod sql.qp/datetime-diff [:postgres :hour] [driver _unit x y] @@ -366,7 +363,7 @@ (defmethod sql.qp/datetime-diff [:postgres :second] [_driver _unit x y] (let [seconds (hx/- (extract :epoch y) (extract :epoch x))] - (hx/->integer (hsql/call :trunc seconds)))) + (hx/->integer (hx/call :trunc seconds)))) (p/defrecord+ RegexMatchFirst [identifier pattern] hformat/ToSql diff --git a/src/metabase/driver/sql/query_processor.clj b/src/metabase/driver/sql/query_processor.clj index 5786ed688e4..9135ef4e992 100644 --- a/src/metabase/driver/sql/query_processor.clj +++ b/src/metabase/driver/sql/query_processor.clj @@ -231,7 +231,7 @@ "Return a HoneySQL form that performs represents addition of some temporal interval to the original `hsql-form`. `unit` is one of the units listed in [[metabase.util.date-2/add-units]]. - (add-interval-honeysql-form :my-driver hsql-form 1 :day) -> (hsql/call :date_add hsql-form 1 (hx/literal 'day')) + (add-interval-honeysql-form :my-driver hsql-form 1 :day) -> (hx/call :date_add hsql-form 1 (hx/literal 'day')) `amount` is usually an integer, but can be floating-point for units like seconds." {:arglists '([driver hsql-form amount unit])} @@ -272,8 +272,8 @@ (cond (zero? offset) day-of-week (neg? offset) (recur driver day-of-week (+ offset 7) mod-fn) - :else (hsql/call :case - (hsql/call := (mod-fn (hx/+ day-of-week offset) 7) 0) 7 + :else (hx/call :case + (hx/call := (mod-fn (hx/+ day-of-week offset) 7) 0) 7 :else (mod-fn (hx/+ day-of-week offset) 7))))) (defmulti quote-style @@ -500,29 +500,29 @@ (defmethod ->honeysql [:sql :count] [driver [_ field]] (if field - (hsql/call :count (->honeysql driver field)) + (hx/call :count (->honeysql driver field)) :%count.*)) -(defmethod ->honeysql [:sql :avg] [driver [_ field]] (hsql/call :avg (->honeysql driver field))) -(defmethod ->honeysql [:sql :median] [driver [_ field]] (hsql/call :median (->honeysql driver field))) -(defmethod ->honeysql [:sql :percentile] [driver [_ field p]] (hsql/call :percentile-cont (->honeysql driver field) (->honeysql driver p))) -(defmethod ->honeysql [:sql :distinct] [driver [_ field]] (hsql/call :distinct-count (->honeysql driver field))) -(defmethod ->honeysql [:sql :stddev] [driver [_ field]] (hsql/call :stddev_pop (->honeysql driver field))) -(defmethod ->honeysql [:sql :var] [driver [_ field]] (hsql/call :var_pop (->honeysql driver field))) -(defmethod ->honeysql [:sql :sum] [driver [_ field]] (hsql/call :sum (->honeysql driver field))) -(defmethod ->honeysql [:sql :min] [driver [_ field]] (hsql/call :min (->honeysql driver field))) -(defmethod ->honeysql [:sql :max] [driver [_ field]] (hsql/call :max (->honeysql driver field))) - -(defmethod ->honeysql [:sql :floor] [driver [_ field]] (hsql/call :floor (->honeysql driver field))) -(defmethod ->honeysql [:sql :ceil] [driver [_ field]] (hsql/call :ceil (->honeysql driver field))) -(defmethod ->honeysql [:sql :round] [driver [_ field]] (hsql/call :round (->honeysql driver field))) -(defmethod ->honeysql [:sql :abs] [driver [_ field]] (hsql/call :abs (->honeysql driver field))) - -(defmethod ->honeysql [:sql :log] [driver [_ field]] (hsql/call :log 10 (->honeysql driver field))) -(defmethod ->honeysql [:sql :exp] [driver [_ field]] (hsql/call :exp (->honeysql driver field))) -(defmethod ->honeysql [:sql :sqrt] [driver [_ field]] (hsql/call :sqrt (->honeysql driver field))) +(defmethod ->honeysql [:sql :avg] [driver [_ field]] (hx/call :avg (->honeysql driver field))) +(defmethod ->honeysql [:sql :median] [driver [_ field]] (hx/call :median (->honeysql driver field))) +(defmethod ->honeysql [:sql :percentile] [driver [_ field p]] (hx/call :percentile-cont (->honeysql driver field) (->honeysql driver p))) +(defmethod ->honeysql [:sql :distinct] [driver [_ field]] (hx/call :distinct-count (->honeysql driver field))) +(defmethod ->honeysql [:sql :stddev] [driver [_ field]] (hx/call :stddev_pop (->honeysql driver field))) +(defmethod ->honeysql [:sql :var] [driver [_ field]] (hx/call :var_pop (->honeysql driver field))) +(defmethod ->honeysql [:sql :sum] [driver [_ field]] (hx/call :sum (->honeysql driver field))) +(defmethod ->honeysql [:sql :min] [driver [_ field]] (hx/call :min (->honeysql driver field))) +(defmethod ->honeysql [:sql :max] [driver [_ field]] (hx/call :max (->honeysql driver field))) + +(defmethod ->honeysql [:sql :floor] [driver [_ field]] (hx/call :floor (->honeysql driver field))) +(defmethod ->honeysql [:sql :ceil] [driver [_ field]] (hx/call :ceil (->honeysql driver field))) +(defmethod ->honeysql [:sql :round] [driver [_ field]] (hx/call :round (->honeysql driver field))) +(defmethod ->honeysql [:sql :abs] [driver [_ field]] (hx/call :abs (->honeysql driver field))) + +(defmethod ->honeysql [:sql :log] [driver [_ field]] (hx/call :log 10 (->honeysql driver field))) +(defmethod ->honeysql [:sql :exp] [driver [_ field]] (hx/call :exp (->honeysql driver field))) +(defmethod ->honeysql [:sql :sqrt] [driver [_ field]] (hx/call :sqrt (->honeysql driver field))) (defmethod ->honeysql [:sql :power] [driver [_ field power]] - (hsql/call :power (->honeysql driver field) (->honeysql driver power))) + (hx/call :power (->honeysql driver field) (->honeysql driver power))) (defn- interval? [expr] (mbql.u/is-clause? :interval expr)) @@ -536,10 +536,10 @@ (->honeysql driver field) intervals) (throw (ex-info "Summing intervals is not supported" {:args args}))) - (apply hsql/call :+ (map (partial ->honeysql driver) args)))) + (apply hx/call :+ (map (partial ->honeysql driver) args)))) -(defmethod ->honeysql [:sql :-] [driver [_ & args]] (apply hsql/call :- (map (partial ->honeysql driver) args))) -(defmethod ->honeysql [:sql :*] [driver [_ & args]] (apply hsql/call :* (map (partial ->honeysql driver) args))) +(defmethod ->honeysql [:sql :-] [driver [_ & args]] (apply hx/call :- (map (partial ->honeysql driver) args))) +(defmethod ->honeysql [:sql :*] [driver [_ & args]] (apply hx/call :* (map (partial ->honeysql driver) args))) ;; for division we want to go ahead and convert any integer args to floats, because something like field / 2 will do ;; integer division and give us something like 1.0 where we would rather see something like 1.5 @@ -553,16 +553,16 @@ (->honeysql driver (if (integer? arg) (double arg) arg)))] - (apply hsql/call :/ + (apply hx/call :/ (->float driver numerator) (for [denominator denominators] - (hsql/call :case - (hsql/call := denominator 0) nil + (hx/call :case + (hx/call := denominator 0) nil :else denominator))))) (defmethod ->honeysql [:sql :sum-where] [driver [_ arg pred]] - (hsql/call :sum (hsql/call :case + (hx/call :sum (hx/call :case (->honeysql driver pred) (->honeysql driver arg) :else 0.0))) @@ -572,49 +572,49 @@ (defmethod ->honeysql [:sql :share] [driver [_ pred]] - (hsql/call :/ (->honeysql driver [:count-where pred]) :%count.*)) + (hx/call :/ (->honeysql driver [:count-where pred]) :%count.*)) (defmethod ->honeysql [:sql :trim] [driver [_ arg]] - (hsql/call :trim (->honeysql driver arg))) + (hx/call :trim (->honeysql driver arg))) (defmethod ->honeysql [:sql :ltrim] [driver [_ arg]] - (hsql/call :ltrim (->honeysql driver arg))) + (hx/call :ltrim (->honeysql driver arg))) (defmethod ->honeysql [:sql :rtrim] [driver [_ arg]] - (hsql/call :rtrim (->honeysql driver arg))) + (hx/call :rtrim (->honeysql driver arg))) (defmethod ->honeysql [:sql :upper] [driver [_ arg]] - (hsql/call :upper (->honeysql driver arg))) + (hx/call :upper (->honeysql driver arg))) (defmethod ->honeysql [:sql :lower] [driver [_ arg]] - (hsql/call :lower (->honeysql driver arg))) + (hx/call :lower (->honeysql driver arg))) (defmethod ->honeysql [:sql :coalesce] [driver [_ & args]] - (apply hsql/call :coalesce (mapv (partial ->honeysql driver) args))) + (apply hx/call :coalesce (mapv (partial ->honeysql driver) args))) (defmethod ->honeysql [:sql :replace] [driver [_ arg pattern replacement]] - (hsql/call :replace (->honeysql driver arg) (->honeysql driver pattern) (->honeysql driver replacement))) + (hx/call :replace (->honeysql driver arg) (->honeysql driver pattern) (->honeysql driver replacement))) (defmethod ->honeysql [:sql :concat] [driver [_ & args]] - (apply hsql/call :concat (mapv (partial ->honeysql driver) args))) + (apply hx/call :concat (mapv (partial ->honeysql driver) args))) (defmethod ->honeysql [:sql :substring] [driver [_ arg start length]] (if length - (hsql/call :substring (->honeysql driver arg) (->honeysql driver start) (->honeysql driver length)) - (hsql/call :substring (->honeysql driver arg) (->honeysql driver start)))) + (hx/call :substring (->honeysql driver arg) (->honeysql driver start) (->honeysql driver length)) + (hx/call :substring (->honeysql driver arg) (->honeysql driver start)))) (defmethod ->honeysql [:sql :length] [driver [_ arg]] - (hsql/call :length (->honeysql driver arg))) + (hx/call :length (->honeysql driver arg))) (defmethod ->honeysql [:sql :case] [driver [_ cases options]] @@ -623,7 +623,7 @@ [[:else (:default options)]])) (apply concat) (mapv (partial ->honeysql driver)) - (apply hsql/call :case))) + (apply hx/call :case))) ;; actual handling of the name is done in the top-level clause handler for aggregations (defmethod ->honeysql [:sql :aggregation-options] @@ -818,7 +818,7 @@ ;; custom implementation? (if (get options :case-sensitive true) [:like field (->honeysql driver value)] - [:like (hsql/call :lower field) (->honeysql driver (update value 1 u/lower-case-en))])) + [:like (hx/call :lower field) (->honeysql driver (update value 1 u/lower-case-en))])) (s/defn ^:private update-string-value :- mbql.s/value [value :- (s/constrained mbql.s/value #(string? (second %)) "string value"), f] @@ -1052,7 +1052,7 @@ from) [raw-identifier] (format-honeysql driver table-identifier)] (if (seq raw-identifier) - [(hsql/raw (format "%s.*" raw-identifier))] + [(hx/raw (format "%s.*" raw-identifier))] [:*]))))) (defn- apply-top-level-clauses diff --git a/src/metabase/models/collection.clj b/src/metabase/models/collection.clj index 29458254254..de0ddcdb60f 100644 --- a/src/metabase/models/collection.clj +++ b/src/metabase/models/collection.clj @@ -8,7 +8,6 @@ [clojure.set :as set] [clojure.string :as str] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [medley.core :as m] [metabase.api.common :as api @@ -612,7 +611,7 @@ ;; we need to update all the descendant collections as well... (db/execute! {:update :collection - :set {:location (hsql/call :replace :location orig-children-location new-children-location)} + :set {:location (hx/call :replace :location orig-children-location new-children-location)} :where [:like :location (str orig-children-location "%")]})))) (s/defn ^:private collection->descendant-ids :- (s/maybe #{su/IntGreaterThanZero}) diff --git a/src/metabase/models/setting/cache.clj b/src/metabase/models/setting/cache.clj index 9ae67bafdbb..b1c334cb567 100644 --- a/src/metabase/models/setting/cache.clj +++ b/src/metabase/models/setting/cache.clj @@ -5,7 +5,6 @@ [clojure.core :as core] [clojure.java.jdbc :as jdbc] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [metabase.db.connection :as mdb.connection] [metabase.util :as u] [metabase.util.honeysql-extensions :as hx] @@ -73,7 +72,7 @@ (log/debug (trs "Updating value of settings-last-updated in DB...")) ;; for MySQL, cast(current_timestamp AS char); for H2 & Postgres, cast(current_timestamp AS text) (let [current-timestamp-as-string-honeysql (hx/cast (if (= (mdb.connection/db-type) :mysql) :char :text) - (hsql/raw "current_timestamp"))] + (hx/raw "current_timestamp"))] ;; attempt to UPDATE the existing row. If no row exists, `update-where!` will return false... (or (db/update-where! 'Setting {:key settings-last-updated-key} :value current-timestamp-as-string-honeysql) ;; ...at which point we will try to INSERT a new row. Note that it is entirely possible two instances can both diff --git a/src/metabase/models/table.clj b/src/metabase/models/table.clj index dce9234c80e..cdef0551635 100644 --- a/src/metabase/models/table.clj +++ b/src/metabase/models/table.clj @@ -1,6 +1,5 @@ (ns metabase.models.table (:require - [honeysql.core :as hsql] [metabase.db.connection :as mdb.connection] [metabase.db.util :as mdb.u] [metabase.driver :as driver] @@ -16,6 +15,7 @@ [metabase.models.serialization.hash :as serdes.hash] [metabase.models.serialization.util :as serdes.util] [metabase.util :as u] + [metabase.util.honeysql-extensions :as hx] [toucan.db :as db] [toucan.models :as models])) @@ -102,11 +102,11 @@ :table_id (u/the-id table) {:order-by (case (:field_order table) :custom [[:custom_position :asc]] - :smart [[(hsql/call :case - (mdb.u/isa :semantic_type :type/PK) 0 - (mdb.u/isa :semantic_type :type/Name) 1 - (mdb.u/isa :semantic_type :type/Temporal) 2 - :else 3) + :smart [[(hx/call :case + (mdb.u/isa :semantic_type :type/PK) 0 + (mdb.u/isa :semantic_type :type/Name) 1 + (mdb.u/isa :semantic_type :type/Temporal) 2 + :else 3) :asc] [:%lower.name :asc]] :database [[:database_position :asc]] diff --git a/src/metabase/server/middleware/session.clj b/src/metabase/server/middleware/session.clj index a2a59bc2fa2..c537b1926c3 100644 --- a/src/metabase/server/middleware/session.clj +++ b/src/metabase/server/middleware/session.clj @@ -3,7 +3,6 @@ (:require [clojure.java.jdbc :as jdbc] [clojure.tools.logging :as log] - [honeysql.core :as hsql] [honeysql.helpers :as hh] [java-time :as t] [metabase.api.common @@ -27,6 +26,7 @@ [metabase.public-settings.premium-features :as premium-features] [metabase.server.request.util :as request.u] [metabase.util :as u] + [metabase.util.honeysql-extensions :as hx] [metabase.util.i18n :as i18n :refer [deferred-trs deferred-tru trs tru]] [ring.util.response :as response] [schema.core :as s] @@ -238,7 +238,7 @@ :left-join [[:core_user :user] [:= :session.user_id :user.id]] :where [:and [:= :user.is_active true] - [:= :session.id (hsql/raw "?")] + [:= :session.id (hx/raw "?")] (let [oldest-allowed (sql.qp/add-interval-honeysql-form db-type :%now (- max-age-minutes) :minute)] [:> :session.created_at oldest-allowed]) [:= :session.anti_csrf_token (case session-type diff --git a/src/metabase/util/honey_sql_1_extensions.clj b/src/metabase/util/honey_sql_1_extensions.clj index 5496b0cb31e..c819eb030e1 100644 --- a/src/metabase/util/honey_sql_1_extensions.clj +++ b/src/metabase/util/honey_sql_1_extensions.clj @@ -255,6 +255,7 @@ (s/defn cast :- TypedHoneySQLForm "Generate a statement like `cast(expr AS sql-type)`. Returns a typed HoneySQL form." [db-type expr] + #_{:clj-kondo/ignore [:discouraged-var]} (-> (hsql/call :cast expr (hsql/raw (name db-type))) (with-type-info {:metabase.util.honeysql-extensions/database-type db-type}))) @@ -266,6 +267,7 @@ Returns a typed HoneySQL form." [sql-type expr] + #_{:clj-kondo/ignore [:discouraged-var]} (-> (hsql/call :cast expr (keyword sql-type)) (with-type-info {:metabase.util.honeysql-extensions/database-type sql-type}))) @@ -294,6 +296,7 @@ (let [arg-db-type (some (fn [arg] (-> arg type-info type-info->db-type)) args)] + #_{:clj-kondo/ignore [:discouraged-var]} (cond-> (apply hsql/call operator args) arg-db-type (with-database-type-info arg-db-type))))) @@ -309,11 +312,13 @@ (defn format "SQL `format` function." [format-str expr] + #_{:clj-kondo/ignore [:discouraged-var]} (hsql/call :format expr (literal format-str))) (defn round "SQL `round` function." [x decimal-places] + #_{:clj-kondo/ignore [:discouraged-var]} (hsql/call :round x decimal-places)) (defn ->date "CAST `x` to a `date`." [x] (maybe-cast :date x)) @@ -325,26 +330,27 @@ (defn ->boolean "CAST `x` to a `boolean` datatype" [x] (maybe-cast :boolean x)) ;;; Random SQL fns. Not all DBs support all these! -(def ^{:arglists '([& exprs])} abs "SQL `abs` function." (partial hsql/call :abs)) -(def ^{:arglists '([& exprs])} ceil "SQL `ceil` function." (partial hsql/call :ceil)) -(def ^{:arglists '([& exprs])} floor "SQL `floor` function." (partial hsql/call :floor)) -(def ^{:arglists '([& exprs])} second "SQL `second` function." (partial hsql/call :second)) -(def ^{:arglists '([& exprs])} minute "SQL `minute` function." (partial hsql/call :minute)) -(def ^{:arglists '([& exprs])} hour "SQL `hour` function." (partial hsql/call :hour)) -(def ^{:arglists '([& exprs])} day "SQL `day` function." (partial hsql/call :day)) -(def ^{:arglists '([& exprs])} week "SQL `week` function." (partial hsql/call :week)) -(def ^{:arglists '([& exprs])} month "SQL `month` function." (partial hsql/call :month)) -(def ^{:arglists '([& exprs])} quarter "SQL `quarter` function." (partial hsql/call :quarter)) -(def ^{:arglists '([& exprs])} year "SQL `year` function." (partial hsql/call :year)) -(def ^{:arglists '([& exprs])} concat "SQL `concat` function." (partial hsql/call :concat)) +(def ^{:arglists '([& exprs])} abs "SQL `abs` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :abs)) +(def ^{:arglists '([& exprs])} ceil "SQL `ceil` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :ceil)) +(def ^{:arglists '([& exprs])} floor "SQL `floor` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :floor)) +(def ^{:arglists '([& exprs])} second "SQL `second` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :second)) +(def ^{:arglists '([& exprs])} minute "SQL `minute` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :minute)) +(def ^{:arglists '([& exprs])} hour "SQL `hour` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :hour)) +(def ^{:arglists '([& exprs])} day "SQL `day` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :day)) +(def ^{:arglists '([& exprs])} week "SQL `week` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :week)) +(def ^{:arglists '([& exprs])} month "SQL `month` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :month)) +(def ^{:arglists '([& exprs])} quarter "SQL `quarter` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :quarter)) +(def ^{:arglists '([& exprs])} year "SQL `year` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :year)) +(def ^{:arglists '([& exprs])} concat "SQL `concat` function." (partial #_{:clj-kondo/ignore [:discouraged-var]} hsql/call :concat)) ;; Etc (Dev Stuff) (extend-protocol pretty/PrettyPrintable honeysql.types.SqlCall (pretty [{fn-name :name, args :args, :as this}] + #_{:clj-kondo/ignore [:discouraged-var]} (with-meta (apply list `hsql/call fn-name args) - (meta this)))) + (meta this)))) (defmethod print-method honeysql.types.SqlCall [call writer] diff --git a/src/metabase/util/honeysql_extensions.clj b/src/metabase/util/honeysql_extensions.clj index ed4e0cff2b2..73e7295bee7 100644 --- a/src/metabase/util/honeysql_extensions.clj +++ b/src/metabase/util/honeysql_extensions.clj @@ -6,6 +6,7 @@ :exclude [+ - / * abs mod inc dec cast concat format second]) (:require + [honeysql.core :as hsql] [metabase.util.honey-sql-1-extensions :as h1x] [metabase.util.honey-sql-2-extensions :as h2x] [schema.core :as s])) @@ -360,3 +361,21 @@ (case *honey-sql-version* 1 (h1x/->AtTimeZone expr zone) 2 (h2x/at-time-zone expr zone))) + +(defn call + "Like [[honeysql.core/call]] but works with either Honey SQL 1 or Honey SQL 2. Prefer using raw Honey SQL 2 code + directly unless you need HoneySQL 1 compatibility." + [f & args] + #_{:clj-kondo/ignore [:discouraged-var]} + (case *honey-sql-version* + 1 (apply hsql/call f args) + 2 (apply vector f args))) + +(defn raw + "Like [[honeysql.core/raw]] but works with either Honey SQL 1 or Honey SQL 2. Prefer using raw Honey SQL 2 code + directly unless you need HoneySQL 1 compatibility." + [x] + #_{:clj-kondo/ignore [:discouraged-var]} + (case *honey-sql-version* + 1 (hsql/raw x) + 2 [:raw x])) diff --git a/test/metabase/async/streaming_response_test.clj b/test/metabase/async/streaming_response_test.clj index 1f7e110b291..0b00d9c0983 100644 --- a/test/metabase/async/streaming_response_test.clj +++ b/test/metabase/async/streaming_response_test.clj @@ -1,4 +1,4 @@ -(ns metabase.async.streaming-response-test +(ns ^:mb/once metabase.async.streaming-response-test (:require [clj-http.client :as http] [clojure.core.async :as a] diff --git a/test/metabase/driver/h2_test.clj b/test/metabase/driver/h2_test.clj index c6c82b52d94..9abf1e0d32e 100644 --- a/test/metabase/driver/h2_test.clj +++ b/test/metabase/driver/h2_test.clj @@ -3,7 +3,6 @@ [clojure.java.jdbc :as jdbc] [clojure.string :as str] [clojure.test :refer :all] - [honeysql.core :as hsql] [metabase.db.spec :as mdb.spec] [metabase.driver :as driver] [metabase.driver.h2 :as h2] @@ -79,17 +78,17 @@ (deftest add-interval-honeysql-form-test (testing "Should convert fractional seconds to milliseconds" - (is (= (hsql/call :dateadd - (hx/literal "millisecond") - (hx/with-database-type-info (hsql/call :cast 100500.0 (hsql/raw "long")) "long") - (hx/with-database-type-info (hsql/call :cast :%now (hsql/raw "datetime")) "datetime")) + (is (= (hx/call :dateadd + (hx/literal "millisecond") + (hx/with-database-type-info (hx/call :cast 100500.0 (hx/raw "long")) "long") + (hx/with-database-type-info (hx/call :cast :%now (hx/raw "datetime")) "datetime")) (sql.qp/add-interval-honeysql-form :h2 :%now 100.5 :second)))) (testing "Non-fractional seconds should remain seconds, but be cast to longs" - (is (= (hsql/call :dateadd - (hx/literal "second") - (hx/with-database-type-info (hsql/call :cast 100.0 (hsql/raw "long")) "long") - (hx/with-database-type-info (hsql/call :cast :%now (hsql/raw "datetime")) "datetime")) + (is (= (hx/call :dateadd + (hx/literal "second") + (hx/with-database-type-info (hx/call :cast 100.0 (hx/raw "long")) "long") + (hx/with-database-type-info (hx/call :cast :%now (hx/raw "datetime")) "datetime")) (sql.qp/add-interval-honeysql-form :h2 :%now 100.0 :second))))) (deftest clob-test diff --git a/test/metabase/driver/postgres_test.clj b/test/metabase/driver/postgres_test.clj index 5810392569b..c657730a943 100644 --- a/test/metabase/driver/postgres_test.clj +++ b/test/metabase/driver/postgres_test.clj @@ -588,8 +588,8 @@ (mt/defdataset ip-addresses [["addresses" [{:field-name "ip", :base-type {:native "inet"}, :effective-type :type/IPAddress}] - [[(hsql/raw "'192.168.1.1'::inet")] - [(hsql/raw "'10.4.4.15'::inet")]]]]) + [[(hx/raw "'192.168.1.1'::inet")] + [(hx/raw "'10.4.4.15'::inet")]]]]) (deftest inet-columns-test (mt/test-driver :postgres @@ -687,62 +687,62 @@ (deftest enums-test (mt/test-driver :postgres (testing "check that values for enum types get wrapped in appropriate CAST() fn calls in `->honeysql`" - (is (= (hx/with-database-type-info (hsql/call :cast "toucan" (keyword "bird type")) "bird type") + (is (= (hx/with-database-type-info (hx/call :cast "toucan" (keyword "bird type")) "bird type") (sql.qp/->honeysql :postgres [:value "toucan" {:database_type "bird type", :base_type :type/PostgresEnum}])))) (do-with-enums-db - (fn [db] - (testing "check that we can actually fetch the enum types from a DB" - (is (= #{(keyword "bird type") :bird_status} - (#'postgres/enum-types :postgres db)))) - - (testing "check that describe-table properly describes the database & base types of the enum fields" - (is (= {:name "birds" - :fields #{{:name "name" - :database-type "varchar" - :base-type :type/Text - :pk? true - :database-position 0 - :database-required true} - {:name "status" - :database-type "bird_status" - :base-type :type/PostgresEnum - :database-position 1 - :database-required true} - {:name "type" - :database-type "bird type" - :base-type :type/PostgresEnum - :database-position 2 - :database-required true}}} - (driver/describe-table :postgres db {:name "birds"})))) - - (testing "check that when syncing the DB the enum types get recorded appropriately" - (let [table-id (db/select-one-id Table :db_id (u/the-id db), :name "birds")] - (is (= #{{:name "name", :database_type "varchar", :base_type :type/Text} - {:name "type", :database_type "bird type", :base_type :type/PostgresEnum} - {:name "status", :database_type "bird_status", :base_type :type/PostgresEnum}} - (set (map (partial into {}) - (db/select [Field :name :database_type :base_type] :table_id table-id))))))) - - (testing "End-to-end check: make sure everything works as expected when we run an actual query" - (let [table-id (db/select-one-id Table :db_id (u/the-id db), :name "birds") - bird-type-field-id (db/select-one-id Field :table_id table-id, :name "type")] - (is (= {:rows [["Rasta" "good bird" "toucan"]] - :native_form {:query (str "SELECT \"public\".\"birds\".\"name\" AS \"name\"," - " \"public\".\"birds\".\"status\" AS \"status\"," - " \"public\".\"birds\".\"type\" AS \"type\" " - "FROM \"public\".\"birds\" " - "WHERE \"public\".\"birds\".\"type\" = CAST('toucan' AS \"bird type\") " - "LIMIT 10") - :params nil}} - (-> (qp/process-query - {:database (u/the-id db) - :type :query - :query {:source-table table-id - :filter [:= [:field (u/the-id bird-type-field-id) nil] "toucan"] - :limit 10}}) - :data - (select-keys [:rows :native_form])))))))))) + (fn [db] + (testing "check that we can actually fetch the enum types from a DB" + (is (= #{(keyword "bird type") :bird_status} + (#'postgres/enum-types :postgres db)))) + + (testing "check that describe-table properly describes the database & base types of the enum fields" + (is (= {:name "birds" + :fields #{{:name "name" + :database-type "varchar" + :base-type :type/Text + :pk? true + :database-position 0 + :database-required true} + {:name "status" + :database-type "bird_status" + :base-type :type/PostgresEnum + :database-position 1 + :database-required true} + {:name "type" + :database-type "bird type" + :base-type :type/PostgresEnum + :database-position 2 + :database-required true}}} + (driver/describe-table :postgres db {:name "birds"})))) + + (testing "check that when syncing the DB the enum types get recorded appropriately" + (let [table-id (db/select-one-id Table :db_id (u/the-id db), :name "birds")] + (is (= #{{:name "name", :database_type "varchar", :base_type :type/Text} + {:name "type", :database_type "bird type", :base_type :type/PostgresEnum} + {:name "status", :database_type "bird_status", :base_type :type/PostgresEnum}} + (set (map (partial into {}) + (db/select [Field :name :database_type :base_type] :table_id table-id))))))) + + (testing "End-to-end check: make sure everything works as expected when we run an actual query" + (let [table-id (db/select-one-id Table :db_id (u/the-id db), :name "birds") + bird-type-field-id (db/select-one-id Field :table_id table-id, :name "type")] + (is (= {:rows [["Rasta" "good bird" "toucan"]] + :native_form {:query (str "SELECT \"public\".\"birds\".\"name\" AS \"name\"," + " \"public\".\"birds\".\"status\" AS \"status\"," + " \"public\".\"birds\".\"type\" AS \"type\" " + "FROM \"public\".\"birds\" " + "WHERE \"public\".\"birds\".\"type\" = CAST('toucan' AS \"bird type\") " + "LIMIT 10") + :params nil}} + (-> (qp/process-query + {:database (u/the-id db) + :type :query + :query {:source-table table-id + :filter [:= [:field (u/the-id bird-type-field-id) nil] "toucan"] + :limit 10}}) + :data + (select-keys [:rows :native_form])))))))))) ;;; ------------------------------------------------ Timezone-related ------------------------------------------------ diff --git a/test/metabase/driver/sql/query_processor_test.clj b/test/metabase/driver/sql/query_processor_test.clj index 9fc4693a6c5..0c9383cfc2a 100644 --- a/test/metabase/driver/sql/query_processor_test.clj +++ b/test/metabase/driver/sql/query_processor_test.clj @@ -217,22 +217,22 @@ (driver/with-driver :h2 (with-redefs [driver/db-start-of-week (constantly :monday) setting/get-value-of-type (constantly :sunday)] - (is (= (hsql/call :dateadd + (is (= (hx/call :dateadd (hx/literal "day") - (hx/with-database-type-info (hsql/call :cast -1 #sql/raw "long") "long") + (hx/with-database-type-info (hx/call :cast -1 #sql/raw "long") "long") (hx/with-database-type-info - (hsql/call :cast - (hsql/call :week (hsql/call :dateadd (hx/literal "day") - (hx/with-database-type-info (hsql/call :cast 1 #sql/raw "long") "long") - (hx/with-database-type-info (hsql/call :cast :created_at #sql/raw "datetime") "datetime"))) + (hx/call :cast + (hx/call :week (hx/call :dateadd (hx/literal "day") + (hx/with-database-type-info (hx/call :cast 1 #sql/raw "long") "long") + (hx/with-database-type-info (hx/call :cast :created_at #sql/raw "datetime") "datetime"))) #sql/raw "datetime") "datetime")) - (sql.qp/adjust-start-of-week :h2 (partial hsql/call :week) :created_at)))) + (sql.qp/adjust-start-of-week :h2 (partial hx/call :week) :created_at)))) (testing "Do we skip the adjustment if offset = 0" (with-redefs [driver/db-start-of-week (constantly :monday) setting/get-value-of-type (constantly :monday)] - (is (= (hsql/call :week :created_at) - (sql.qp/adjust-start-of-week :h2 (partial hsql/call :week) :created_at))))))) + (is (= (hx/call :week :created_at) + (sql.qp/adjust-start-of-week :h2 (partial hx/call :week) :created_at))))))) (defn- query-on-dataset-with-nils [query] diff --git a/test/metabase/models/setting/cache_test.clj b/test/metabase/models/setting/cache_test.clj index da89e987de1..28a23c3b5af 100644 --- a/test/metabase/models/setting/cache_test.clj +++ b/test/metabase/models/setting/cache_test.clj @@ -1,7 +1,6 @@ (ns metabase.models.setting.cache-test (:require [clojure.test :refer :all] - [honeysql.core :as hsql] [metabase.db :as mdb] [metabase.models.setting :refer [Setting]] [metabase.models.setting-test :as setting-test] @@ -9,6 +8,7 @@ [metabase.public-settings :as public-settings] [metabase.test :as mt] [metabase.test.fixtures :as fixtures] + [metabase.util.honeysql-extensions :as hx] [toucan.db :as db])) (use-fixtures :once (fixtures/initialize :db)) @@ -26,12 +26,12 @@ updating our locally cached value.." [] (db/update-where! Setting {:key setting.cache/settings-last-updated-key} - :value (hsql/raw (case (mdb/db-type) - ;; make it one second in the future so we don't end up getting an exact match when we try to test - ;; to see if things update below - :h2 "cast(dateadd('second', 1, current_timestamp) AS text)" - :mysql "cast((current_timestamp + interval 1 second) AS char)" - :postgres "cast((current_timestamp + interval '1 second') AS text)")))) + :value (hx/raw (case (mdb/db-type) + ;; make it one second in the future so we don't end up getting an exact match when we try to test + ;; to see if things update below + :h2 "cast(dateadd('second', 1, current_timestamp) AS text)" + :mysql "cast((current_timestamp + interval 1 second) AS char)" + :postgres "cast((current_timestamp + interval '1 second') AS text)")))) (defn- simulate-another-instance-updating-setting! [setting-name new-value] (if new-value diff --git a/test/metabase/query_processor_test/nested_queries_test.clj b/test/metabase/query_processor_test/nested_queries_test.clj index a33df807190..1b312a9c227 100644 --- a/test/metabase/query_processor_test/nested_queries_test.clj +++ b/test/metabase/query_processor_test/nested_queries_test.clj @@ -20,6 +20,7 @@ [metabase.query-processor.middleware.permissions :as qp.perms] [metabase.test :as mt] [metabase.util :as u] + [metabase.util.honeysql-extensions :as hx] [schema.core :as s] [toucan.db :as db])) @@ -356,14 +357,14 @@ [:source.LONGITUDE :LONGITUDE] [:source.PRICE :PRICE]] :from [[venues-source-honeysql :source]] - :where [:= (hsql/raw "\"source\".\"BIRD.ID\"") 1] + :where [:= (hx/raw "\"source\".\"BIRD.ID\"") 1] :limit 10}) (qp/compile - {:database (mt/id) - :type :query - :query {:source-query {:source-table (mt/id :venues)} - :filter [:= [:field "BIRD.ID" {:base-type :type/Integer}] 1] - :limit 10}})) + {:database (mt/id) + :type :query + :query {:source-query {:source-table (mt/id :venues)} + :filter [:= [:field "BIRD.ID" {:base-type :type/Integer}] 1] + :limit 10}})) (str "make sure that dots in field literal identifiers get handled properly so you can't reference fields " "from other tables using them")) (is (= (honeysql->sql @@ -375,14 +376,14 @@ [:source.PRICE :PRICE]] :from [[venues-source-honeysql :source]] :where [:and - [:>= (hsql/raw "\"source\".\"BIRD.ID\"") (t/zoned-date-time "2017-01-01T00:00Z[UTC]")] - [:< (hsql/raw "\"source\".\"BIRD.ID\"") (t/zoned-date-time "2017-01-08T00:00Z[UTC]")]] + [:>= (hx/raw "\"source\".\"BIRD.ID\"") (t/zoned-date-time "2017-01-01T00:00Z[UTC]")] + [:< (hx/raw "\"source\".\"BIRD.ID\"") (t/zoned-date-time "2017-01-08T00:00Z[UTC]")]] :limit 10}) (qp/compile - (mt/mbql-query venues - {:source-query {:source-table $$venues} - :filter [:= !week.*BIRD.ID/DateTime "2017-01-01"] - :limit 10}))) + (mt/mbql-query venues + {:source-query {:source-table $$venues} + :filter [:= !week.*BIRD.ID/DateTime "2017-01-01"] + :limit 10}))) "make sure that field-literals work as DateTimeFields")) (deftest aggregatation-references-test diff --git a/test/metabase/query_processor_test/timezones_test.clj b/test/metabase/query_processor_test/timezones_test.clj index 96238b43df0..9a0a734b03f 100644 --- a/test/metabase/query_processor_test/timezones_test.clj +++ b/test/metabase/query_processor_test/timezones_test.clj @@ -2,7 +2,6 @@ (:require [clojure.set :as set] [clojure.test :refer :all] - [honeysql.core :as hsql] [java-time :as t] [metabase.driver :as driver] [metabase.driver.sql.query-processor :as sql.qp] @@ -121,8 +120,8 @@ :from [(table-identifier :users)] :where [:between (field-identifier :users :last_login) - (hsql/raw "{{date1}}") - (hsql/raw "{{date2}}")] + (hx/raw "{{date1}}") + (hx/raw "{{date2}}")] :order-by [[(field-identifier :users :id) :asc]]}) :template-tags {:date1 {:name "date1" :display_name "Date1" :type "date"} :date2 {:name "date2" :display_name "Date2" :type "date"}}} @@ -138,7 +137,7 @@ {:select (mapv (partial field-identifier :users) [:id :name :last_login]) :from [(table-identifier :users)] - :where (hsql/raw "{{ts_range}}") + :where (hx/raw "{{ts_range}}") :order-by [[(field-identifier :users :id) :asc]]}) :template-tags {:ts_range {:name "ts_range" :display_name "Timestamp Range" @@ -154,7 +153,7 @@ {:select (mapv (partial field-identifier :users) [:id :name :last_login]) :from [(table-identifier :users)] - :where (hsql/raw "{{just_a_date}}") + :where (hx/raw "{{just_a_date}}") :order-by [[(field-identifier :users :id) :asc]]}) :template-tags {:just_a_date {:name "just_a_date" :display_name "Just A Date" -- GitLab