(ns metabase.driver.sql-jdbc.sync.interface
  (:require
   [honey.sql :as sql]
   [metabase.driver :as driver]
   [metabase.driver.sql-jdbc.quoting :refer [with-quoting  quote-identifier]]
   [metabase.driver.sql.query-processor :as sql.qp]))

Return a reducible sequence of maps containing information about the active tables/views, collections, or equivalent that currently exist in a database. Each map should contain the key :name, which is the string name of the table. For databases that have a concept of schemas, this map should also include the string name of the table's :schema.

Two different implementations are provided in this namespace: fast-active-tables (the default), and post-filtered-active-tables. You should be fine using the default, but refer to the documentation for those functions for more details on the differences.

(defmulti active-tables
  {:added "0.37.1"
   :arglists '([driver
                ^java.sql.Connection connection
                ^String schema-inclusion-filters
                ^String schema-exclusion-filters])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Return set of string names of schemas to skip syncing tables from.

(defmulti excluded-schemas
  {:added "0.37.1" :arglists '([driver])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Check if we have SELECT privileges for given table.

Default impl is in [[metabase.driver.sql-jdbc.sync.describe-database]].

(defmulti have-select-privilege?
  {:added "0.37.1" :arglists '([driver ^java.sql.Connection connection ^String table-schema ^String table-name])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Return a reducible sequence of string names of schemas that should be synced for the given database. Schemas for which the current DB user has no SELECT permissions should be filtered out. The default implementation will fetch a sequence of all schema names from the JDBC database metadata and filter out any schemas in excluded-schemas, along with any that shouldn't be included based on the given inclusion and exclusion patterns (see the metabase.driver.sync namespace for full explanation).

(defmulti filtered-syncable-schemas
  {:changelog-test/ignore true
   :added "0.43.0"
   :arglists '([driver
                ^java.sql.Connection connection
                ^java.sql.DatabaseMetaData metadata
                ^String schema-inclusion-patterns
                ^String schema-exclusion-patterns])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Given a native DB column type (as a keyword), return the corresponding Field base-type, which should derive from :type/*. You can use pattern-based-database-type->base-type in this namespace to implement this using regex patterns.

(defmulti database-type->base-type
  {:added "0.37.1" :arglists '([driver database-type])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Attempt to determine the semantic-type of a field given the column name and native type. For example, the Postgres driver can mark Postgres JSON type columns as :type/SerializedJSON semantic type.

database-type and column-name will be strings.

(defmulti column->semantic-type
  {:added "0.37.1" :arglists '([driver database-type column-name])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

SELECT columns from a given table so we can get column metadata. By default doesn't return any rows. This can be overriden because SQLite is silly and only returns column information for views if the query returns a non-zero number of rows.

(fallback-metadata-query :postgres "mydatabase" "public" "mytable") ;; -> ["SELECT * FROM mydatabase.public.mytable WHERE 1 <> 1 LIMIT 0"]

(defmulti fallback-metadata-query
  {:added "0.37.1" :arglists '([driver db-name-or-nil schema-name table-name])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

JDBC-specific version of of [[metabase.driver/db-default-timezone]] that takes a [[clojure.java.jdbc]] connection spec rather than a set of DB details. If an implementation of this method is provided, it will be used automatically in the default :sql-jdbc implementation of [[metabase.driver/db-default-timezone]].

This exists so we can reuse this code with the application database without having to create a new Connection pool for the application DB.

DEPRECATED: you can implement [[metabase.driver/db-default-timezone]] directly; use [[metabase.driver.sql-jdbc.execute/do-with-connection-with-options]] to get a java.sql.Connection for a Database.

(defmulti db-default-timezone
  {:added "0.38.0", :arglists '([driver jdbc-spec]), :deprecated "0.48.0"}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)
#_{:clj-kondo/ignore [:deprecated-var]}
(defmethod db-default-timezone :sql-jdbc
  [_driver _jdbc-spec]
  nil)

Return information about the nestable columns in a table. Required for drivers that support :nested-field-columns. Results should match the [[metabase.sync.interface/NestedFCMetadata]] schema.

(defmulti describe-nested-field-columns
  {:added "0.43.0", :arglists '([driver database table])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Returns the rows of data as arrays needed to populate the table_privileges table with the DB connection's current user privileges. The data contains the privileges that the user has on the given database. The privileges include select, insert, update, and delete.

The rows have the following keys and value types: - role :- [:maybe :string] - schema :- [:maybe :string] - table :- :string - select :- :boolean - update :- :boolean - insert :- :boolean - delete :- :boolean

Either: (1) role is null, corresponding to the privileges of the DB connection's current user (2) role is not null, corresponding to the privileges of the role

(defmulti current-user-table-privileges
  {:added "0.49.0" :arglists '([driver conn-spec & args])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)

Generate the query to be used with [[driver/alter-columns!]].

(defmulti alter-columns-sql
  {:added "0.49.0", :arglists '([driver db-id table-name column-definitions])}
  driver/dispatch-on-initialized-driver
  :hierarchy #'driver/hierarchy)
(defmethod alter-columns-sql :sql-jdbc
  [driver table-name column-definitions]
  (with-quoting driver
    (first (sql/format {:alter-table  (keyword table-name)
                        :alter-column (map (fn [[column-name type-and-constraints]]
                                             (vec (cons (quote-identifier column-name)
                                                        (if (string? type-and-constraints)
                                                          [[:raw type-and-constraints]]
                                                          type-and-constraints))))
                                           column-definitions)}
                       :quoted true
                       :dialect (sql.qp/quote-style driver)))))