Skip to content
Snippets Groups Projects
Unverified Commit 72485588 authored by Cam Saul's avatar Cam Saul Committed by GitHub
Browse files

MLv2: use kebab-case keys in Clojure & camelCase in JS (#30248)

* MLv2: use kebab-case keys in Clojure & camelCase in JS

* Revert changes to tests
parent 52d9a018
No related branches found
No related tags found
No related merge requests found
Showing
with 163 additions and 143 deletions
......@@ -162,8 +162,9 @@
toucan.models/model? {:message "Use mdb.u/toucan-model? instead of toucan.models/model?"}}
:discouraged-namespace
{clojure.tools.logging {:message "Use metabase.util.log instead of clojure.tools.logging directly"}
metabase.util.jvm {:message "All of metabase.util.jvm is re-exported from metabase.util; prefer that"}}
{camel-snake-kebab.core {:message "CSK is not Turkish-safe, use the versions in metabase.util instead."}
clojure.tools.logging {:message "Use metabase.util.log instead of clojure.tools.logging directly"}
metabase.util.jvm {:message "All of metabase.util.jvm is re-exported from metabase.util; prefer that"}}
:unresolved-var
{:exclude
......@@ -712,10 +713,16 @@
;; to the new stricter rules from day 1
metabase-lib
{:linters
{:docstring-leading-trailing-whitespace {:level :warning}
:reduce-without-init {:level :warning}
:used-underscored-binding {:level :warning}
:single-key-in {:level :warning}
:keyword-binding {:level :warning}
:shadowed-var {:level :warning}
:metabase/deftest-not-marked-parallel-or-synchronized {:level :warning}}}}}
{:docstring-leading-trailing-whitespace {:level :warning}
:reduce-without-init {:level :warning}
:used-underscored-binding {:level :warning}
:single-key-in {:level :warning}
:keyword-binding {:level :warning}
:shadowed-var {:level :warning}
:metabase/deftest-not-marked-parallel-or-synchronized {:level :warning}
;; eventually we should do this for the whole codebase, but the args are in the opposite order so switching them
;; all at once isn't trivial, at least we can stop using it in new code.
:discouraged-var
{medley.core/map-keys {:message "Use clojure.core/update-keys"}
medley.core/map-vals {:message "Use clojure.core/update-vals"}}}}}}
......@@ -91,14 +91,14 @@
{{env user-dir}}
```"
(:require
[camel-snake-kebab.core :as csk]
[clojure.edn :as edn]
[clojure.spec.alpha :as s]
[clojure.string :as str]
[clojure.walk :as walk]
[environ.core :as env]
[metabase-enterprise.advanced-config.file.databases]
[metabase-enterprise.advanced-config.file.interface :as advanced-config.file.i]
[metabase-enterprise.advanced-config.file.interface
:as advanced-config.file.i]
[metabase-enterprise.advanced-config.file.settings]
[metabase-enterprise.advanced-config.file.users]
[metabase.driver.common.parameters]
......@@ -183,7 +183,7 @@
(defmethod expand-parsed-template-form 'env
[[_template-type env-var-name]]
(get *env* (csk/->kebab-case-keyword env-var-name)))
(get *env* (keyword (u/->kebab-case-en env-var-name))))
(defmulti ^:private expand-template-str-part
{:arglists '([part])}
......
......@@ -37,17 +37,17 @@ describe("order by", () => {
expect(ML.displayInfo(query, ordersID)).toEqual(
expect.objectContaining({
name: "ID",
display_name: "ID",
effective_type: "type/BigInteger",
semantic_type: "type/PK",
is_calculated: false,
is_from_join: false,
is_from_previous_stage: false,
is_implicitly_joinable: false,
displayName: "ID",
effectiveType: "type/BigInteger",
semanticType: "type/PK",
isCalculated: false,
isFromJoin: false,
isFromPreviousStage: false,
isImplicitlyJoinable: false,
table: {
name: "ORDERS",
display_name: "Orders",
is_source_table: true,
displayName: "Orders",
isSourceTable: true,
},
}),
);
......@@ -59,17 +59,17 @@ describe("order by", () => {
expect(ML.displayInfo(query, productsTitle)).toEqual(
expect.objectContaining({
name: "TITLE",
display_name: "Title",
effective_type: "type/Text",
semantic_type: "type/Category",
is_calculated: false,
is_from_join: false,
is_from_previous_stage: false,
is_implicitly_joinable: true,
displayName: "Title",
effectiveType: "type/Text",
semanticType: "type/Category",
isCalculated: false,
isFromJoin: false,
isFromPreviousStage: false,
isImplicitlyJoinable: true,
table: {
name: "PRODUCTS",
display_name: "Products",
is_source_table: false,
displayName: "Products",
isSourceTable: false,
},
}),
);
......@@ -104,8 +104,8 @@ describe("order by", () => {
(columnMetadata: ML.ColumnMetadata) => {
const displayInfo = ML.displayInfo(query, columnMetadata);
return (
displayInfo.display_name === "Title" &&
displayInfo.table?.display_name === "Product Model"
displayInfo.displayName === "Title" &&
displayInfo.table?.displayName === "Product Model"
);
},
);
......@@ -113,9 +113,9 @@ describe("order by", () => {
expect(ML.displayInfo(query, productsTitle as ML.ColumnMetadata)).toEqual(
expect.objectContaining({
name: field.name,
display_name: field.display_name,
effective_type: field.base_type,
table: { name: "Product Model", display_name: "Product Model" },
displayName: field.display_name,
effectiveType: field.base_type,
table: { name: "Product Model", displayName: "Product Model" },
}),
);
});
......
......@@ -25,32 +25,33 @@ export type ColumnGroup = unknown & { _opaque: typeof ColumnGroup };
export type TableDisplayInfo = {
name: string;
display_name: string;
is_source_table: boolean;
is_from_join: boolean;
is_implicitly_joinable: boolean;
displayName: string;
isSourceTable: boolean;
isFromJoin: boolean;
isImplicitlyJoinable: boolean;
};
type TableInlineDisplayInfo = Pick<
TableDisplayInfo,
"name" | "display_name" | "is_source_table"
"name" | "displayName" | "isSourceTable"
>;
export type ColumnDisplayInfo = {
name: string;
display_name: string;
fk_reference_name?: string;
semantic_type?: string | null;
effective_type: string;
displayName: string;
fkReferenceName?: string;
// TODO -- pretty sure the types were removed?
semanticType?: string | null;
effectiveType: string;
is_calculated: boolean;
is_from_join: boolean;
is_implicitly_joinable: boolean;
isFromJoin: boolean;
isImplicitlyJoinable: boolean;
table?: TableInlineDisplayInfo;
};
export type OrderByClauseDisplayInfo = Pick<
ColumnDisplayInfo,
"name" | "display_name" | "effective_type" | "semantic_type" | "table"
"name" | "displayName" | "effectiveType" | "semanticType" | "table"
> & {
direction: OrderByDirection;
};
......@@ -81,7 +81,7 @@ function QueryColumnPicker({
}
function renderItemName(item: ColumnListItem) {
return item.display_name;
return item.displayName;
}
function omitItemDescription() {
......@@ -95,17 +95,17 @@ function renderItemIcon(item: ColumnListItem) {
function getGroupName(groupInfo: Lib.ColumnDisplayInfo | Lib.TableDisplayInfo) {
const columnInfo = groupInfo as Lib.ColumnDisplayInfo;
const tableInfo = groupInfo as Lib.TableDisplayInfo;
return columnInfo.fk_reference_name || singularize(tableInfo.display_name);
return columnInfo.fkReferenceName || singularize(tableInfo.displayName);
}
function getGroupIcon(groupInfo: Lib.ColumnDisplayInfo | Lib.TableDisplayInfo) {
if ((groupInfo as Lib.TableDisplayInfo).is_source_table) {
if ((groupInfo as Lib.TableDisplayInfo).isSourceTable) {
return "table";
}
if (groupInfo.is_from_join) {
if (groupInfo.isFromJoin) {
return "join_left_outer";
}
if (groupInfo.is_implicitly_joinable) {
if (groupInfo.isImplicitlyJoinable) {
return "connections";
}
return;
......
......@@ -62,7 +62,7 @@ describe("QueryColumnPicker", () => {
it("should allow picking a column", async () => {
const { sampleColumn, sampleColumnInfo, onSelect, onClose } = setup();
userEvent.click(screen.getByText(sampleColumnInfo.display_name));
userEvent.click(screen.getByText(sampleColumnInfo.displayName));
expect(onSelect).toHaveBeenCalledWith(sampleColumn);
expect(onClose).toHaveBeenCalled();
......
......@@ -103,7 +103,7 @@ function SortDisplayName({
}}
>
<Icon name={icon} />
<span>{displayInfo.display_name}</span>
<span>{displayInfo.displayName}</span>
</SortDirectionButton>
);
}
......
......@@ -58,7 +58,7 @@ describe("SortStep", () => {
setup(createMockNotebookStep({ topLevelQuery: query }));
expect(screen.getByText(columnInfo.display_name)).toBeInTheDocument();
expect(screen.getByText(columnInfo.displayName)).toBeInTheDocument();
expect(getIcon("arrow_up")).toBeInTheDocument();
expect(queryIcon("arrow_down")).not.toBeInTheDocument();
});
......@@ -68,7 +68,7 @@ describe("SortStep", () => {
setup(createMockNotebookStep({ topLevelQuery: query }));
expect(screen.getByText(columnInfo.display_name)).toBeInTheDocument();
expect(screen.getByText(columnInfo.displayName)).toBeInTheDocument();
expect(getIcon("arrow_down")).toBeInTheDocument();
expect(queryIcon("arrow_up")).not.toBeInTheDocument();
});
......@@ -98,7 +98,7 @@ describe("SortStep", () => {
userEvent.click(screen.getByText("Created At"));
const orderBy = gerRecentOrderByClause();
expect(orderBy.display_name).toBe("Created At");
expect(orderBy.displayName).toBe("Created At");
expect(orderBy.direction).toBe("asc");
});
......@@ -112,7 +112,7 @@ describe("SortStep", () => {
const orderBy = gerRecentOrderByClause();
expect(orderBy.direction).toBe("desc");
expect(orderBy.display_name).toBe(columnInfo.display_name);
expect(orderBy.displayName).toBe(columnInfo.displayName);
});
it("should change ordered field", () => {
......@@ -121,11 +121,11 @@ describe("SortStep", () => {
createMockNotebookStep({ topLevelQuery: query }),
);
userEvent.click(screen.getByText(columnInfo.display_name));
userEvent.click(screen.getByText(columnInfo.displayName));
userEvent.click(screen.getByText("Created At"));
const orderBy = gerRecentOrderByClause();
expect(orderBy.display_name).toBe("Created At");
expect(orderBy.displayName).toBe("Created At");
});
it("should remove an order by", () => {
......
......@@ -90,8 +90,9 @@
;;; -------------------------------------------------- Loading Data --------------------------------------------------
(defmethod ddl.i/format-name :bigquery-cloud-sdk [_ table-or-field-name]
(u/snake-key table-or-field-name))
(defmethod ddl.i/format-name :bigquery-cloud-sdk
[_driver table-or-field-name]
(str/replace table-or-field-name #"-" "_"))
(defn- create-dataset! [^String dataset-id]
{:pre [(seq dataset-id)]}
......
......@@ -15,7 +15,6 @@
[metabase.test.data.sql-jdbc.execute :as execute]
[metabase.test.data.sql-jdbc.load-data :as load-data]
[metabase.test.data.sql.ddl :as ddl]
[metabase.util :as u]
[metabase.util.log :as log])
(:import
(java.sql Connection DriverManager PreparedStatement)))
......@@ -147,7 +146,7 @@
(defmethod sql.tx/qualified-name-components :presto-jdbc
;; use the default schema from the in-memory connector
([_ _db-name] [test-catalog-name "default"])
([_ _db-name] [test-catalog-name "default"])
([_ db-name table-name] [test-catalog-name "default" (tx/db-qualified-table-name db-name table-name)])
([_ db-name table-name field-name] [test-catalog-name "default" (tx/db-qualified-table-name db-name table-name) field-name]))
......@@ -172,8 +171,9 @@
(is (= "CREATE TABLE \"test_data\".\"default\".\"categories\" (\"id\" INTEGER, \"name\" VARCHAR) ;"
(sql.tx/create-table-sql :presto-jdbc db-def table-def))))))
(defmethod ddl.i/format-name :presto-jdbc [_ table-or-field-name]
(u/snake-key table-or-field-name))
(defmethod ddl.i/format-name :presto-jdbc
[_driver table-or-field-name]
(str/replace table-or-field-name #"-" "_"))
;; Presto doesn't support FKs, at least not adding them via DDL
(defmethod sql.tx/add-fk-sql :presto-jdbc
......
(ns metabase.analytics.snowplow
"Functions for sending Snowplow analytics events"
(:require
[clojure.string :as str]
[java-time :as t]
[medley.core :as m]
[metabase.config :as config]
[metabase.models.setting :as setting :refer [defsetting Setting]]
[metabase.models.user :refer [User]]
[metabase.public-settings :as public-settings]
[metabase.util :as u]
[metabase.util.date-2 :as u.date]
[metabase.util.i18n :refer [deferred-tru trs]]
[metabase.util.log :as log]
......@@ -172,7 +172,7 @@
(defn- normalize-kw
[kw]
(-> kw u/snake-key name))
(-> kw name (str/replace #"-" "_")))
(defn- payload
"A SelfDescribingJson object containing the provided event data, which can be included as the payload for an
......
......@@ -50,7 +50,7 @@
(defn- format-prefix
"Used to build an environment variable."
[env-var]
(str "MB_" (u/screaming-snake-case (name (:name env-var)))))
(str "MB_" (u/->SCREAMING_SNAKE_CASE_EN (name (:name env-var)))))
(defn- format-heading
"Takes an integer and a string and creates a Markdown heading of level n."
......
(ns metabase.domain-entities.converters
(:require
[camel-snake-kebab.core :as csk]
[malli.core :as mc]
[malli.transform :as mtx]))
[malli.transform :as mtx]
[metabase.util :as u]))
(defn- decode-map [schema _]
(let [by-prop (into {} (for [[map-key props] (mc/children schema)]
[(or (get props :js/prop)
(csk/->snake_case_string map-key))
(u/->snake_case_en (u/qualified-name map-key)))
{:map-key map-key}]))]
{:enter (fn [x]
(cond
......@@ -16,7 +16,7 @@
(into {} (for [prop (js-keys x)
:let [js-val (unchecked-get x prop)
map-key (or (get-in by-prop [prop :map-key])
(csk/->kebab-case-keyword prop))]]
(keyword (u/->kebab-case-en prop)))]]
[map-key js-val]))))
:leave (fn [x]
(if (object? x)
......@@ -127,7 +127,7 @@
:when (:js/prop props)]
[k (:js/prop props)]))
keyenc (fn [k] (or (get js-props k)
(csk/->snake_case_string k)))]
(u/->snake_case_en (u/qualified-name k))))]
{:leave #(encode-map % keyenc)}))}
:map-of {:leave #(encode-map % name)}})}))
......
......@@ -17,7 +17,7 @@
"Given `:metadata/field` column metadata for an aggregation, construct an `:aggregation` reference."
[metadata :- lib.metadata/ColumnMetadata]
(let [options {:lib/uuid (str (random-uuid))
:effective-type ((some-fn :effective_type :base_type) metadata)}
:effective-type ((some-fn :effective-type :base-type) metadata)}
index (::aggregation-index metadata)]
(assert (integer? index) "Metadata for an aggregation reference should include ::aggregation-index")
[:aggregation options index]))
......@@ -51,9 +51,9 @@
{:lib/source :source/aggregations
::aggregation-index index}
(when base-type
{:base_type base-type})
{:base-type base-type})
(when effective-type
{:effective_type effective-type}))))
{:effective-type effective-type}))))
;;; TODO -- merge this stuff into `defop` somehow.
......
......@@ -4,29 +4,37 @@
[metabase.lib.metadata :as lib.metadata]
[metabase.lib.metadata.calculation :as lib.metadata.calculation]
[metabase.lib.query :as lib.query]
[metabase.lib.schema :as lib.schema]
[metabase.lib.schema.id :as lib.schema.id]
[metabase.util :as u]
[metabase.util.humanization :as u.humanization]
[metabase.util.malli :as mu]))
(defmethod lib.metadata.calculation/display-name-method :metadata/card
[_query _stage-number card-metadata _style]
((some-fn :display_name :name) card-metadata))
((some-fn :display-name :name) card-metadata))
(defmethod lib.metadata.calculation/metadata-method :metadata/card
[_query _stage-number {card-name :name, display-name :display_name, :as card-metadata}]
[_query _stage-number {card-name :name, :keys [display-name], :as card-metadata}]
(cond-> card-metadata
(not display-name) (assoc :display_name (u.humanization/name->human-readable-name :simple card-name))))
(not display-name) (assoc :display-name (u.humanization/name->human-readable-name :simple card-name))))
(defn- infer-results-metadata [metadata-provider card-query]
(lib.metadata.calculation/metadata (lib.query/query metadata-provider (lib.convert/->pMBQL card-query))))
(mu/defn ^:private infer-results-metadata
[metadata-providerable :- lib.metadata/MetadataProviderable
card-query :- :map]
(lib.metadata.calculation/metadata (lib.query/query metadata-providerable (lib.convert/->pMBQL card-query))))
(defn- card-metadata-columns
[query card]
(when-let [result-metadata (or (:result_metadata card)
(def ^:private Card
[:map
{:error/message "Card with :dataset-query"}
[:dataset-query :map]])
(mu/defn ^:private card-metadata-columns
[metadata-providerable :- lib.metadata/MetadataProviderable
card :- Card]
(when-let [result-metadata (or (:result-metadata card)
(:fields card)
(infer-results-metadata (:lib/metadata query) (:dataset_query card)))]
;; Card `result_metadata` SHOULD be a sequence of column infos, but just to be safe handle a map that
(infer-results-metadata metadata-providerable (:dataset-query card)))]
;; Card `result-metadata` SHOULD be a sequence of column infos, but just to be safe handle a map that
;; contains` :columns` as well.
(when-let [cols (not-empty (cond
(map? result-metadata) (:columns result-metadata)
......@@ -34,8 +42,8 @@
(mapv (fn [col]
(merge
(when-let [field-id (:id col)]
(lib.metadata/field query field-id))
col
(lib.metadata/field metadata-providerable field-id))
(update-keys col u/->kebab-case-en)
{:lib/type :metadata/field
:lib/source :source/card
:lib/card-id (:id card)
......@@ -44,12 +52,12 @@
(mu/defn saved-question-metadata :- [:maybe [:sequential {:min 1} lib.metadata.calculation/ColumnMetadataWithSource]]
"Metadata associated with a Saved Question with `card-id`."
[query :- ::lib.schema/query
card-id :- ::lib.schema.id/card]
;; it seems like in some cases (unit tests) the FE is renaming `:result_metadata` to `:fields`, not 100% sure why
[metadata-providerable :- lib.metadata/MetadataProviderable
card-id :- ::lib.schema.id/card]
;; it seems like in some cases (unit tests) the FE is renaming `:result-metadata` to `:fields`, not 100% sure why
;; but handle that case anyway. (#29739)
(when-let [card (lib.metadata/card query card-id)]
(card-metadata-columns query card)))
(when-let [card (lib.metadata/card metadata-providerable card-id)]
(card-metadata-columns metadata-providerable card)))
(defmethod lib.metadata.calculation/default-columns-method :metadata/card
[query _stage-number card unique-name-fn]
......
......@@ -53,20 +53,20 @@
(lib.metadata.calculation/display-info query stage-number table)))
;; for multi-stage queries return an empty string (#30108)
(when (next (:stages query))
{:display_name ""})
{:display-name ""})
;; if this is a native query or something else that doesn't have a source Table or source Card then use the
;; stage display name.
{:display_name (lib.metadata.calculation/display-name query stage-number stage)}))
{:is_from_join false
:is_implicitly_joinable false})
{:display-name (lib.metadata.calculation/display-name query stage-number stage)}))
{:is-from-join false
:is-implicitly-joinable false})
:group-type/join.explicit
(merge
(let [join-alias (:join-alias column-group)]
(when-let [join (lib.join/resolve-join query stage-number join-alias)]
(lib.metadata.calculation/display-info query stage-number join)))
{:is_from_join true
:is_implicitly_joinable false})
{:is-from-join true
:is-implicitly-joinable false})
:group-type/join.implicit
(merge
......@@ -78,16 +78,16 @@
;; This is very intentional: one table might have several FKs to one foreign table, each with different
;; meaning (eg. ORDERS.customer_id vs. ORDERS.supplier_id both linking to a PEOPLE table).
;; See #30109 for more details.
(assoc field-info :fk_reference_name (lib.util/strip-id (:display_name field-info))))))
{:is_from_join false
:is_implicitly_joinable true})))
(assoc field-info :fk-reference-name (lib.util/strip-id (:display-name field-info))))))
{:is-from-join false
:is-implicitly-joinable true})))
(mu/defn ^:private column-group-info :- [:map [::group-type GroupType]]
"The value we should use to `group-by` inside [[group-columns]]."
[{source :lib/source, :as column-metadata} :- lib.metadata/ColumnMetadata]
(case source
:source/implicitly-joinable
{::group-type :group-type/join.implicit, :fk-field-id (:fk_field_id column-metadata)}
{::group-type :group-type/join.implicit, :fk-field-id (:fk-field-id column-metadata)}
:source/joins
{::group-type :group-type/join.explicit, :join-alias (lib.join/current-join-alias column-metadata)}
......
......@@ -254,6 +254,12 @@
[input]
(aggregation->legacy-MBQL input))
(defn- stage-metadata->legacy-metadata [stage-metadata]
(into []
(comp (map #(update-keys % u/->snake_case_en))
(map ->legacy-MBQL))
(:columns stage-metadata)))
(defn- chain-stages [{:keys [stages]}]
;; :source-metadata aka :lib/stage-metadata is handled differently in the two formats.
;; In legacy, an inner query might have both :source-query, and :source-metadata giving the metadata for that nested
......@@ -264,7 +270,7 @@
(let [inner-query (first (reduce (fn [[inner stage-metadata] stage]
[(cond-> (->legacy-MBQL stage)
inner (assoc :source-query inner)
stage-metadata (assoc :source-metadata (mapv ->legacy-MBQL (:columns stage-metadata))))
stage-metadata (assoc :source-metadata (stage-metadata->legacy-metadata stage-metadata)))
;; Get the :lib/stage-metadata off the original pMBQL stage, not the converted one.
(:lib/stage-metadata stage)])
nil
......
......@@ -14,6 +14,7 @@
[metabase.lib.schema.expression :as lib.schema.expression]
[metabase.lib.schema.temporal-bucketing
:as lib.schema.temporal-bucketing]
[metabase.lib.temporal-bucket :as lib.temporal-bucket]
[metabase.lib.util :as lib.util]
[metabase.shared.util.i18n :as i18n]
[metabase.types :as types]
......@@ -23,8 +24,8 @@
"Given `:metadata/field` column metadata for an expression, construct an `:expression` reference."
[metadata :- lib.metadata/ColumnMetadata]
(let [options {:lib/uuid (str (random-uuid))
:base-type (:base_type metadata)
:effective-type ((some-fn :effective_type :base_type) metadata)}]
:base-type (:base-type metadata)
:effective-type ((some-fn :effective-type :base-type) metadata)}]
[:expression options (:name metadata)]))
(mu/defn resolve-expression :- ::lib.schema.expression/expression
......@@ -49,8 +50,8 @@
[query stage-number [_expression _opts expression-name, :as expression-ref]]
{:lib/type :metadata/field
:name expression-name
:display_name (lib.metadata.calculation/display-name query stage-number expression-ref)
:base_type (lib.metadata.calculation/type-of query stage-number expression-ref)
:display-name (lib.metadata.calculation/display-name query stage-number expression-ref)
:base-type (lib.metadata.calculation/type-of query stage-number expression-ref)
:lib/source :source/expressions})
(defmethod lib.metadata.calculation/display-name-method :dispatch-type/integer
......@@ -133,17 +134,13 @@
(for [arg args]
(lib.metadata.calculation/type-of query stage-number arg))))
;;; TODO -- this stuff should probably be moved into [[metabase.lib.temporal-bucket]]
(defn- interval-unit-str [amount unit]
(clojure.core/case unit
:millisecond (i18n/trun "millisecond" "milliseconds" (clojure.core/abs amount))
:second (i18n/trun "second" "seconds" (clojure.core/abs amount))
:minute (i18n/trun "minute" "minutes" (clojure.core/abs amount))
:hour (i18n/trun "hour" "hours" (clojure.core/abs amount))
:day (i18n/trun "day" "days" (clojure.core/abs amount))
:week (i18n/trun "week" "weeks" (clojure.core/abs amount))
:month (i18n/trun "month" "months" (clojure.core/abs amount))
:quarter (i18n/trun "quarter" "quarters" (clojure.core/abs amount))
:year (i18n/trun "year" "years" (clojure.core/abs amount))))
;; this uses [[clojure.string/lower-case]] so its in the user's locale in the browser rather than always using
;; English lower-casing rules.
#_{:clj-kondo/ignore [:discouraged-var]}
(str/lower-case (lib.temporal-bucket/describe-temporal-unit amount unit)))
(mu/defn ^:private interval-display-name :- ::lib.schema.common/non-blank-string
"e.g. something like \"- 2 days\""
......@@ -253,7 +250,7 @@
(-> (lib.metadata.calculation/metadata query stage-number expression-definition)
(assoc :lib/source :source/expressions
:name expression-name
:display_name expression-name)))))))
:display-name expression-name)))))))
(defmethod lib.ref/ref-method :expression
[expression-clause]
......
......@@ -93,9 +93,9 @@
[_field {:keys [join-alias], :as opts} id-or-name, :as _field-clause] :- :mbql.clause/field]
(merge
(when-let [base-type (:base-type opts)]
{:base_type base-type})
{:base-type base-type})
(when-let [effective-type ((some-fn :effective-type :base-type) opts)]
{:effective_type effective-type})
{:effective-type effective-type})
;; TODO -- some of the other stuff in `opts` probably ought to be merged in here as well. Also, if the Field is
;; temporally bucketed, the base-type/effective-type would probably be affected, right? We should probably be
;; taking that into consideration?
......@@ -113,9 +113,9 @@
"If this is a nested column, add metadata about the parent column."
[query :- ::lib.schema/query
metadata :- lib.metadata/ColumnMetadata]
(let [parent-metadata (lib.metadata/field query (:parent_id metadata))
(let [parent-metadata (lib.metadata/field query (:parent-id metadata))
{parent-name :name} (cond->> parent-metadata
(:parent_id parent-metadata) (add-parent-column-metadata query))]
(:parent-id parent-metadata) (add-parent-column-metadata query))]
(update metadata :name (fn [field-name]
(str parent-name \. field-name)))))
......@@ -127,7 +127,7 @@
(if (and temporal-unit
(contains? lib.schema.temporal-bucketing/datetime-extraction-units temporal-unit))
:type/Integer
((some-fn :effective_type :base_type) column-metadata)))
((some-fn :effective-type :base-type) column-metadata)))
(defmethod lib.metadata.calculation/type-of-method :metadata/field
[_query _stage-number column-metadata]
......@@ -150,30 +150,30 @@
metadata (merge
{:lib/type :metadata/field}
field-metadata
{:display_name (or (:display-name opts)
{:display-name (or (:display-name opts)
(lib.metadata.calculation/display-name query stage-number field-ref))}
(when effective-type
{:effective_type effective-type})
{:effective-type effective-type})
(when base-type
{:base_type base-type})
{:base-type base-type})
(when temporal-unit
{::temporal-unit temporal-unit})
(when join-alias
{::join-alias join-alias})
(when source-field
{:fk_field_id source-field}))]
{:fk-field-id source-field}))]
(cond->> metadata
(:parent_id metadata) (add-parent-column-metadata query))))
(:parent-id metadata) (add-parent-column-metadata query))))
;;; this lives here as opposed to [[metabase.lib.metadata]] because that namespace is more of an interface namespace
;;; and moving this there would cause circular references.
(defmethod lib.metadata.calculation/display-name-method :metadata/field
[query stage-number {field-display-name :display_name
[query stage-number {field-display-name :display-name
field-name :name
temporal-unit :unit
join-alias :source_alias
fk-field-id :fk_field_id
table-id :table_id
fk-field-id :fk-field-id
table-id :table-id
:as _field-metadata} style]
(let [field-display-name (or field-display-name
(u.humanization/name->human-readable-name :simple field-name))
......@@ -200,7 +200,7 @@
(if-let [field-metadata (cond-> (resolve-field-metadata query stage-number field-clause)
join-alias (assoc :source_alias join-alias)
temporal-unit (assoc :unit temporal-unit)
source-field (assoc :fk_field_id source-field))]
source-field (assoc :fk-field-id source-field))]
(lib.metadata.calculation/display-name query stage-number field-metadata style)
;; mostly for the benefit of JS, which does not enforce the Malli schemas.
(i18n/tru "[Unknown Field]")))
......@@ -225,7 +225,7 @@
(when (= (:lib/source field-metadata) :source/card)
(when-let [card-id (:lib/card-id field-metadata)]
(when-let [card (lib.metadata/card query card-id)]
{:table {:name (:name card), :display_name (:name card)}})))))
{:table {:name (:name card), :display-name (:name card)}})))))
(defmethod lib.temporal-bucket/temporal-bucket-method :field
[[_tag opts _id-or-name]]
......@@ -274,7 +274,7 @@
(defmethod lib.temporal-bucket/available-temporal-buckets-method :metadata/field
[_query _stage-number field-metadata]
(let [effective-type ((some-fn :effective_type :base_type) field-metadata)]
(let [effective-type ((some-fn :effective-type :base-type) field-metadata)]
(cond
(isa? effective-type :type/DateTime) lib.schema.temporal-bucketing/datetime-bucketing-units
(isa? effective-type :type/Date) lib.schema.temporal-bucketing/date-bucketing-units
......@@ -310,13 +310,13 @@
:source/expressions (lib.expression/column-metadata->expression-ref metadata)
(let [options (merge
{:lib/uuid (str (random-uuid))
:base-type (:base_type metadata)
:base-type (:base-type metadata)
:effective-type (column-metadata-effective-type metadata)}
(when-let [join-alias (::join-alias metadata)]
{:join-alias join-alias})
(when-let [temporal-unit (::temporal-unit metadata)]
{:temporal-unit temporal-unit})
(when-let [source-field-id (:fk_field_id metadata)]
(when-let [source-field-id (:fk-field-id metadata)]
{:source-field source-field-id})
;; TODO -- binning options.
)
......@@ -325,7 +325,7 @@
(:name metadata)
(or (:id metadata) (:name metadata)))])))
(defn- implicit-join-name [query {fk-field-id :fk_field_id, table-id :table_id, :as _field-metadata}]
(defn- implicit-join-name [query {:keys [fk-field-id table-id], :as _field-metadata}]
(when (and fk-field-id table-id)
(when-let [table-metadata (lib.metadata/table query table-id)]
(let [table-name (:name table-metadata)
......
......@@ -69,7 +69,7 @@
[query _stage-number {[first-stage] :stages, :as _join} _style]
(if-let [source-table (:source-table first-stage)]
(if (integer? source-table)
(:display_name (lib.metadata/table query source-table))
(:display-name (lib.metadata/table query source-table))
;; handle card__<id> source tables.
(let [card-id (lib.util/string-table-id->card-id source-table)]
(i18n/tru "Saved Question #{0}" card-id)))
......@@ -78,7 +78,7 @@
(defmethod lib.metadata.calculation/display-info-method :mbql/join
[query stage-number join]
(let [display-name (lib.metadata.calculation/display-name query stage-number join)]
{:name (or (:alias join) display-name), :display_name display-name}))
{:name (or (:alias join) display-name), :display-name display-name}))
(mu/defn ^:private column-from-join-fields :- lib.metadata.calculation/ColumnMetadataWithSource
"For a column that comes from a join `:fields` list, add or update metadata as needed, e.g. include join name in the
......@@ -89,7 +89,7 @@
join-alias :- ::lib.schema.common/non-blank-string]
(let [column-metadata (assoc column-metadata :source_alias join-alias)
col (-> (assoc column-metadata
:display_name (lib.metadata.calculation/display-name query stage-number column-metadata)
:display-name (lib.metadata.calculation/display-name query stage-number column-metadata)
:lib/source :source/joins)
(with-join-alias join-alias))]
(assert (= (current-join-alias col) join-alias))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment