diff --git a/src/metabase/api/activity.clj b/src/metabase/api/activity.clj index 721cb03ceafa9668afe9054d8df014ebde8d946f..054653acf5bf98d012e44be31ccdb94410014b2c 100644 --- a/src/metabase/api/activity.clj +++ b/src/metabase/api/activity.clj @@ -25,7 +25,6 @@ (defendpoint GET "/recent_views" "Get the list of 15 things the current user has been viewing most recently." [] - ;; use a custom Korma query because we are doing some groupings and aggregations ;; expected output of the query is a single row per unique model viewed by the current user ;; including a `:max_ts` which has the most recent view timestamp of the item and `:cnt` which has total views ;; and we order the results by most recently viewed then hydrate the basic details of the model diff --git a/src/metabase/cmd/load_from_h2.clj b/src/metabase/cmd/load_from_h2.clj index 327002d2c59b306f4f988fef9ab662f34b4de24f..72d0b1406fe38ecfad005b05327bab84e83c7d0f 100644 --- a/src/metabase/cmd/load_from_h2.clj +++ b/src/metabase/cmd/load_from_h2.clj @@ -91,7 +91,7 @@ (print (color/blue \.)) (flush) (k/insert e (k/values (if (= e DashboardCard) - ;; mini-HACK to fix korma/h2 lowercasing these couple attributes + ;; mini-HACK to fix h2 lowercasing these couple attributes ;; luckily this is the only place in our schema where we have camel case names (mapv #(set/rename-keys % {:sizex :sizeX, :sizey :sizeY}) chunk) chunk)))) diff --git a/src/metabase/db.clj b/src/metabase/db.clj index e340d24d04f1869b4f2a9318185f9664e73b601e..dda0074c133a4c842cca01c4338baf721edc5c5d 100644 --- a/src/metabase/db.clj +++ b/src/metabase/db.clj @@ -8,11 +8,11 @@ (honeysql [core :as hsql] [format :as hformat] [helpers :as h]) - (korma [core :as k] - [db :as kdb]) + [korma.db :as kdb] [medley.core :as m] [ring.util.codec :as codec] [metabase.config :as config] + [metabase.db.spec :as dbspec] [metabase.models.interface :as models] [metabase.util :as u] metabase.util.honeysql-extensions) ; this needs to be loaded so the `:h2` quoting style gets added @@ -87,15 +87,15 @@ :password (config/config-str :mb-db-pass)})))) (defn jdbc-details - "Takes our own MB details map and formats them properly for connection details for Korma / JDBC." + "Takes our own MB details map and formats them properly for connection details for JDBC." [db-details] {:pre [(map? db-details)]} ;; TODO: it's probably a good idea to put some more validation here and be really strict about what's in `db-details` (case (:type db-details) - :h2 (kdb/h2 (assoc db-details :naming {:keys s/lower-case - :fields s/upper-case})) - :mysql (kdb/mysql (assoc db-details :db (:dbname db-details))) - :postgres (kdb/postgres (assoc db-details :db (:dbname db-details))))) + :h2 (dbspec/h2 (assoc db-details :naming {:keys s/lower-case + :fields s/upper-case})) + :mysql (dbspec/mysql (assoc db-details :db (:dbname db-details))) + :postgres (dbspec/postgres (assoc db-details :db (:dbname db-details))))) ;; ## MIGRATE @@ -188,7 +188,7 @@ (throw (java.lang.Exception. "Database requires manual upgrade.")))) (log/info "Database Migrations Current ... ✅") - ;; Establish our 'default' Korma DB Connection + ;; Establish our 'default' DB Connection (kdb/default-connection (kdb/create-db (jdbc-details db-details))) ;; Do any custom code-based migrations now that the db structure is up to date @@ -269,7 +269,7 @@ (def ^:private ^:dynamic *call-count* "Atom used as a counter for DB calls when enabled. - This number isn't *perfectly* accurate, only mostly; DB calls made directly to JDBC or via old korma patterns won't be logged." + This number isn't *perfectly* accurate, only mostly; DB calls made directly to JDBC won't be logged." nil) (defn do-with-call-counting diff --git a/src/metabase/db/spec.clj b/src/metabase/db/spec.clj new file mode 100644 index 0000000000000000000000000000000000000000..0df8b032fef678076b5b7868f2a7c263451cd951 --- /dev/null +++ b/src/metabase/db/spec.clj @@ -0,0 +1,65 @@ +(ns metabase.db.spec + "Functions for creating JDBC DB specs for a given engine.") + +(defn postgres + "Create a database specification for a postgres database. Opts should include + keys for :db, :user, and :password. You can also optionally set host and + port." + [{:keys [host port db make-pool?] + :or {host "localhost", port 5432, db "", make-pool? true} + :as opts}] + (merge {:classname "org.postgresql.Driver" ; must be in classpath + :subprotocol "postgresql" + :subname (str "//" host ":" port "/" db) + :make-pool? make-pool?} + (dissoc opts :host :port :db))) + +(defn mysql + "Create a database specification for a mysql database. Opts should include keys + for :db, :user, and :password. You can also optionally set host and port. + Delimiters are automatically set to \"`\"." + [{:keys [host port db make-pool?] + :or {host "localhost", port 3306, db "", make-pool? true} + :as opts}] + (merge {:classname "com.mysql.jdbc.Driver" ; must be in classpath + :subprotocol "mysql" + :subname (str "//" host ":" port "/" db) + :delimiters "`" + :make-pool? make-pool?} + (dissoc opts :host :port :db))) + +(defn mssql + "Create a database specification for a mssql database. Opts should include keys + for :db, :user, and :password. You can also optionally set host and port." + [{:keys [user password db host port make-pool?] + :or {user "dbuser", password "dbpassword", db "", host "localhost", port 1433, make-pool? true} + :as opts}] + (merge {:classname "com.microsoft.sqlserver.jdbc.SQLServerDriver" ; must be in classpath + :subprotocol "sqlserver" + :subname (str "//" host ":" port ";database=" db ";user=" user ";password=" password) + :make-pool? make-pool?} + (dissoc opts :host :port :db))) + +(defn sqlite3 + "Create a database specification for a SQLite3 database. Opts should include a + key for :db which is the path to the database file." + [{:keys [db make-pool?] + :or {db "sqlite.db", make-pool? true} + :as opts}] + (merge {:classname "org.sqlite.JDBC" ; must be in classpath + :subprotocol "sqlite" + :subname db + :make-pool? make-pool?} + (dissoc opts :db))) + +(defn h2 + "Create a database specification for a h2 database. Opts should include a key + for :db which is the path to the database file." + [{:keys [db make-pool?] + :or {db "h2.db", make-pool? true} + :as opts}] + (merge {:classname "org.h2.Driver" ; must be in classpath + :subprotocol "h2" + :subname db + :make-pool? make-pool?} + (dissoc opts :db))) diff --git a/src/metabase/driver/bigquery.clj b/src/metabase/driver/bigquery.clj index 86cdbc18188c62a54909f078caa89f94013326ba..1e39ed334c1c0f257086e751c8e99536c2b51eeb 100644 --- a/src/metabase/driver/bigquery.clj +++ b/src/metabase/driver/bigquery.clj @@ -5,10 +5,9 @@ [clojure.tools.logging :as log] (honeysql [core :as hsql] [helpers :as h]) - [korma.db :as kdb] - (metabase [config :as config] - [db :as db] - [driver :as driver]) + [metabase.config :as config] + [metabase.db :as db] + [metabase.driver :as driver] [metabase.driver.generic-sql :as sql] [metabase.driver.generic-sql.query-processor :as sqlqp] (metabase.models [database :refer [Database]] diff --git a/src/metabase/driver/generic_sql.clj b/src/metabase/driver/generic_sql.clj index 9124430ac176b81c78022de3b860bd86c5829d3f..7e327b4853162e278456e9d81b4c45c03504ce10 100644 --- a/src/metabase/driver/generic_sql.clj +++ b/src/metabase/driver/generic_sql.clj @@ -53,10 +53,10 @@ "Given a `Database` DETAILS-MAP, return a JDBC connection spec.") (current-datetime-fn [this] - "*OPTIONAL*. Korma form that should be used to get the current `DATETIME` (or equivalent). Defaults to `:%now`.") + "*OPTIONAL*. HoneySQL form that should be used to get the current `DATETIME` (or equivalent). Defaults to `:%now`.") (date [this, ^Keyword unit, field-or-value] - "Return a korma form for truncating a date or timestamp field or value to a given resolution, or extracting a date component.") + "Return a HoneySQL form for truncating a date or timestamp field or value to a given resolution, or extracting a date component.") (excluded-schemas ^java.util.Set [this] "*OPTIONAL*. Set of string names of schemas to skip syncing tables from.") @@ -73,9 +73,9 @@ Return `nil` to prevent FIELD from being aliased.") (prepare-value [this, ^Value value] - "*OPTIONAL*. Prepare a value (e.g. a `String` or `Integer`) that will be used in a korma form. By default, this returns VALUE's `:value` as-is, which + "*OPTIONAL*. Prepare a value (e.g. a `String` or `Integer`) that will be used in a HoneySQL form. By default, this returns VALUE's `:value` as-is, which is eventually passed as a parameter in a prepared statement. Drivers such as BigQuery that don't support prepared statements can skip this - behavior by returning a korma `raw` form instead, or other drivers can perform custom type conversion as appropriate.") + behavior by returning a HoneySQL `raw` form instead, or other drivers can perform custom type conversion as appropriate.") (quote-style ^clojure.lang.Keyword [this] "*OPTIONAL*. Return the quoting style that should be used by [HoneySQL](https://github.com/jkk/honeysql) when building a SQL statement. @@ -99,7 +99,7 @@ (hsql/call :length (hx/cast :VARCHAR field-key))") (unix-timestamp->timestamp [this, field-or-value, ^Keyword seconds-or-milliseconds] - "Return a korma form appropriate for converting a Unix timestamp integer field or value to an proper SQL `Timestamp`. + "Return a HoneySQL form appropriate for converting a Unix timestamp integer field or value to an proper SQL `Timestamp`. SECONDS-OR-MILLISECONDS refers to the resolution of the int in question and with be either `:seconds` or `:milliseconds`.")) @@ -159,7 +159,7 @@ (defn escape-field-name - "Escape dots in a field name so Korma doesn't get confused and separate them. Returns a keyword." + "Escape dots in a field name so HoneySQL doesn't get confused and separate them. Returns a keyword." ^clojure.lang.Keyword [k] (keyword (hx/escape-dots (name k)))) @@ -439,7 +439,7 @@ (defn- db->korma-db - "Return a Korma DB spec for Metabase DATABASE." + "Return a DB spec for Metabase DATABASE." [{:keys [details engine], :as database}] (let [spec (connection-details->spec (driver/engine->driver engine) details)] (assoc (create-db spec) @@ -453,7 +453,7 @@ (name (hx/escape-dots (name s)))))))) (defn korma-entity - "Return a Korma entity for [DB and] TABLE. + "Return a entity for [DB and] TABLE. (-> (Table :id 100) korma-entity diff --git a/src/metabase/driver/h2.clj b/src/metabase/driver/h2.clj index e5ab944ffd27ba3617558e58911227488c538bc2..05112669c25144fca60ce2542d31859c755cd17e 100644 --- a/src/metabase/driver/h2.clj +++ b/src/metabase/driver/h2.clj @@ -2,8 +2,8 @@ ;; TODO - This namespace should be reworked to use `u/drop-first-arg` like newer drivers (:require [clojure.string :as s] [honeysql.core :as hsql] - [korma.db :as kdb] [metabase.db :as db] + [metabase.db.spec :as dbspec] [metabase.driver :as driver] [metabase.driver.generic-sql :as sql] [metabase.util :as u] @@ -104,8 +104,8 @@ "ACCESS_MODE_DATA" "r"})))) (defn- connection-details->spec [_ details] - (kdb/h2 (if db/*allow-potentailly-unsafe-connections* details - (update details :db connection-string-set-safe-options)))) + (dbspec/h2 (if db/*allow-potentailly-unsafe-connections* details + (update details :db connection-string-set-safe-options)))) (defn- unix-timestamp->timestamp [_ expr seconds-or-milliseconds] diff --git a/src/metabase/driver/mysql.clj b/src/metabase/driver/mysql.clj index a0538a0c4605aa2982d0c5b315fc7020606ca122..4a279c0b4292761259edb5c28bc1fb4af3fe4392 100644 --- a/src/metabase/driver/mysql.clj +++ b/src/metabase/driver/mysql.clj @@ -2,7 +2,7 @@ (:require (clojure [set :as set] [string :as s]) [honeysql.core :as hsql] - [korma.db :as kdb] + [metabase.db.spec :as dbspec] [metabase.driver :as driver] [metabase.driver.generic-sql :as sql] [metabase.util :as u] @@ -58,7 +58,7 @@ (defn- connection-details->spec [details] (-> details (set/rename-keys {:dbname :db}) - kdb/mysql + dbspec/mysql (update :subname #(str % connection-args-string (when-not (:ssl details) "&useSSL=false"))))) ; newer versions of MySQL will complain if you don't explicitly disable SSL diff --git a/src/metabase/driver/postgres.clj b/src/metabase/driver/postgres.clj index bb03b648fcc5c72443d3f956ca788d4381cef5d6..fe56e61346dd8fdb6a9d3d1a2df672346bec95fd 100644 --- a/src/metabase/driver/postgres.clj +++ b/src/metabase/driver/postgres.clj @@ -5,7 +5,7 @@ [string :as s]) [clojure.tools.logging :as log] [honeysql.core :as hsql] - [korma.db :as kdb] + [metabase.db.spec :as dbspec] [metabase.driver :as driver] [metabase.driver.generic-sql :as sql] [metabase.util :as u] @@ -103,7 +103,7 @@ ssl-params disable-ssl-params)) (rename-keys {:dbname :db}) - kdb/postgres)) + dbspec/postgres)) (defn- unix-timestamp->timestamp [expr seconds-or-milliseconds] (case seconds-or-milliseconds diff --git a/src/metabase/driver/redshift.clj b/src/metabase/driver/redshift.clj index a08b3e412ca0cb5b7132e50183a548c7efbd4f5b..50bad0c50561283582d4b8bd65246dee304258ab 100644 --- a/src/metabase/driver/redshift.clj +++ b/src/metabase/driver/redshift.clj @@ -2,16 +2,16 @@ "Amazon Redshift Driver." (:require [clojure.java.jdbc :as jdbc] [honeysql.core :as hsql] - [korma.db :as kdb] - (metabase [config :as config] - [driver :as driver]) + [metabase.config :as config] + [metabase.db.spec :as dbspec] + [metabase.driver :as driver] (metabase.driver [generic-sql :as sql] [postgres :as postgres]) [metabase.util :as u] [metabase.util.honeysql-extensions :as hx])) (defn- connection-details->spec [details] - (kdb/postgres (merge details postgres/ssl-params))) ; always connect to redshift over SSL + (dbspec/postgres (merge details postgres/ssl-params))) ; always connect to redshift over SSL (defn- date-interval [unit amount] (hsql/call :+ :%getdate (hsql/raw (format "INTERVAL '%d %s'" (int amount) (name unit))))) diff --git a/src/metabase/driver/sqlite.clj b/src/metabase/driver/sqlite.clj index f7c5a893e8faf0da9bb016bf3bdd7d891428ed5f..0f080076bf79d81ac0248c72420494985e0d79b7 100644 --- a/src/metabase/driver/sqlite.clj +++ b/src/metabase/driver/sqlite.clj @@ -2,8 +2,8 @@ (:require [clojure.set :as set] (honeysql [core :as hsql] [format :as hformat]) - [korma.db :as kdb] [metabase.config :as config] + [metabase.db.spec :as dbspec] [metabase.driver :as driver] [metabase.driver.generic-sql :as sql] [metabase.util :as u] @@ -143,7 +143,7 @@ (merge (sql/ISQLDriverDefaultsMixin) {:active-tables sql/post-filtered-active-tables :column->base-type (sql/pattern-based-column->base-type pattern->type) - :connection-details->spec (u/drop-first-arg kdb/sqlite3) + :connection-details->spec (u/drop-first-arg dbspec/sqlite3) :current-datetime-fn (constantly (hsql/raw "datetime('now')")) :date (u/drop-first-arg date) :prepare-value (u/drop-first-arg prepare-value) diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj index d040b04e42506bb3c2f322421138b6965665cb61..79d611560cfd8fe0bdf02cf0a0b2b810678e0b6c 100644 --- a/src/metabase/models/interface.clj +++ b/src/metabase/models/interface.clj @@ -295,7 +295,7 @@ :tag (symbol (str (namespace-munge *ns*) \. instance)) :arglists ''([] [id] [& kvs]) :doc (or docstr - (format "Korma entity for '%s' table; instance of %s." (name table-name) instance))) + (format "Entity for '%s' table; instance of %s." (name table-name) instance))) (-> (k/create-entity ~(name entity)) (k/table ~table-name) (assoc ::entity true) diff --git a/test/metabase/sync_database_test.clj b/test/metabase/sync_database_test.clj index 8fb3f002026d02aa5d072698ec582ce124e8fbc2..4ab6a16ce4a09b257addd4acb6be85ac5d5ad7a9 100644 --- a/test/metabase/sync_database_test.clj +++ b/test/metabase/sync_database_test.clj @@ -54,11 +54,8 @@ (driver/register-driver! :sync-test (SyncTestDriver.)) -(def ^:private users-table (delay (Table, :name "USERS"))) -(def ^:private venues-table (delay (Table (id :venues)))) -(def ^:private korma-users-table (delay (korma-entity @users-table))) -(def ^:private users-name-field (delay (Field (id :users :name)))) +(def ^:private venues-table (delay (Table (id :venues)))) (defn- table-details [table] (into {} (-> (dissoc table :db :pk_field :field_values) diff --git a/test/metabase/test/data/generic_sql.clj b/test/metabase/test/data/generic_sql.clj index e9bec764bb30f7b5921582ff9887fec14001cb56..1e666c20bb40289e0eb31b7e6a668451a97995e7 100644 --- a/test/metabase/test/data/generic_sql.clj +++ b/test/metabase/test/data/generic_sql.clj @@ -52,7 +52,7 @@ ;; Other optional methods (korma-entity [this, ^DatabaseDefinition dbdef, ^TableDefinition tabledef] - "*Optional* Return a korma-entity for TABLEDEF.") + "*Optional* Return an entity for TABLEDEF.") (prepare-identifier [this, ^String identifier] "*OPTIONAL*. Prepare an identifier, such as a Table or Field name, when it is used in a SQL query. @@ -172,7 +172,7 @@ ;; Oracle doesn't understand the normal syntax for inserting multiple rows at a time so we'll insert them one-at-a-time instead) (defn load-data-get-rows - "Get a sequence of row maps for use in a korma `insert` when loading table data." + "Get a sequence of row maps for use in a `insert!` when loading table data." [driver dbdef tabledef] (let [fields-for-insert (mapv (comp keyword :field-name) (:field-definitions tabledef))]