diff --git a/frontend/src/metabase-lib/lib/Question.ts b/frontend/src/metabase-lib/lib/Question.ts index 92832a3aef74cefcf82db940b0011d2ca0687cf3..0102ebf89823f8ec1d96e97b443512ea1f5f3b5a 100644 --- a/frontend/src/metabase-lib/lib/Question.ts +++ b/frontend/src/metabase-lib/lib/Question.ts @@ -24,7 +24,7 @@ import { } from "metabase-lib/lib/Dimension"; import Mode from "metabase-lib/lib/Mode"; import { isStandard } from "metabase-lib/lib/queries/utils/filter"; -import { isFK } from "metabase/lib/schema_metadata"; +import { isFK } from "metabase-lib/lib/types/utils/isa"; import { memoizeClass, sortObject } from "metabase-lib/lib/utils"; /* eslint-enable import/order */ diff --git a/frontend/src/metabase-lib/lib/metadata/Field.ts b/frontend/src/metabase-lib/lib/metadata/Field.ts index 7423ab83eff71811d53fbe9afda2f0dd749fb23d..ed1d617bc27a7597ea93244b048f84fc18d38e4e 100644 --- a/frontend/src/metabase-lib/lib/metadata/Field.ts +++ b/frontend/src/metabase-lib/lib/metadata/Field.ts @@ -4,6 +4,12 @@ import _ from "underscore"; import moment from "moment-timezone"; import { formatField, stripId } from "metabase/lib/formatting"; +import { + getIconForField, + getFilterOperators, +} from "metabase/lib/schema_metadata"; +import type { FieldFingerprint } from "metabase-types/api/field"; +import type { Field as FieldRef } from "metabase-types/types/Query"; import { isDate, isTime, @@ -28,11 +34,7 @@ import { isPK, isFK, isEntityName, - getIconForField, - getFilterOperators, -} from "metabase/lib/schema_metadata"; -import type { FieldFingerprint } from "metabase-types/api/field"; -import type { Field as FieldRef } from "metabase-types/types/Query"; +} from "metabase-lib/lib/types/utils/isa"; import { getFieldValues } from "metabase-lib/lib/queries/utils/field"; import { createLookupByProperty, memoizeClass } from "metabase-lib/lib/utils"; import type StructuredQuery from "metabase-lib/lib/queries/StructuredQuery"; diff --git a/frontend/src/metabase-lib/lib/queries/drills/foreign-key-drill.js b/frontend/src/metabase-lib/lib/queries/drills/foreign-key-drill.js index deff4b191cf7ae2b5179bc448916d7ffa4c018f6..6f1c8884e3033e71740291f720c467f8cc63215b 100644 --- a/frontend/src/metabase-lib/lib/queries/drills/foreign-key-drill.js +++ b/frontend/src/metabase-lib/lib/queries/drills/foreign-key-drill.js @@ -1,5 +1,5 @@ import { stripId } from "metabase/lib/formatting/strings"; -import { isFK, isPK } from "metabase-lib/lib/types/utils/isa"; +import { isTypeFK, isTypePK } from "metabase-lib/lib/types/utils/isa"; export function foreignKeyDrill({ question, clicked }) { const query = question.query(); @@ -14,7 +14,7 @@ export function foreignKeyDrill({ question, clicked }) { } const { column } = clicked; - if (isPK(column.semantic_type) || !isFK(column.semantic_type)) { + if (isTypePK(column.semantic_type) || !isTypeFK(column.semantic_type)) { return null; } diff --git a/frontend/src/metabase-lib/lib/queries/drills/pivot-drill.js b/frontend/src/metabase-lib/lib/queries/drills/pivot-drill.js index 55753f00ad0748c600b85ac54e8d61853802a7df..6a645638e6aa034c2fe57c124ca1ba262fd5f49e 100644 --- a/frontend/src/metabase-lib/lib/queries/drills/pivot-drill.js +++ b/frontend/src/metabase-lib/lib/queries/drills/pivot-drill.js @@ -1,4 +1,8 @@ -import { isAddress, isCategory, isDate } from "metabase/lib/schema_metadata"; +import { + isAddress, + isCategory, + isDate, +} from "metabase-lib/lib/types/utils/isa"; function pivotDrill({ question, clicked, fieldFilter }) { const query = question.query(); diff --git a/frontend/src/metabase-lib/lib/queries/drills/quick-filter-drill.js b/frontend/src/metabase-lib/lib/queries/drills/quick-filter-drill.js index 0fcef5f8f715e8d6fb5e1aa0c8811566eb0fc952..ce3f0ca1b7372dd1eb9e42ea7a082ad2b1ea162d 100644 --- a/frontend/src/metabase-lib/lib/queries/drills/quick-filter-drill.js +++ b/frontend/src/metabase-lib/lib/queries/drills/quick-filter-drill.js @@ -1,5 +1,10 @@ -import { isDate, isNumeric } from "metabase/lib/schema_metadata"; -import { isa, isFK, isPK } from "metabase-lib/lib/types/utils/isa"; +import { + isa, + isTypeFK, + isTypePK, + isDate, + isNumeric, +} from "metabase-lib/lib/types/utils/isa"; import { TYPE } from "metabase-lib/lib/types/constants"; import { isLocalField } from "metabase-lib/lib/queries/utils"; @@ -18,7 +23,7 @@ export function quickFilterDrill({ question, clicked }) { } const { column } = clicked; - if (isPK(column.semantic_type) || isFK(column.semantic_type)) { + if (isTypePK(column.semantic_type) || isTypeFK(column.semantic_type)) { return null; } diff --git a/frontend/src/metabase-lib/lib/queries/utils/actions.js b/frontend/src/metabase-lib/lib/queries/utils/actions.js index 2e4d8d0181e2d0937f8a889984240bf84129d219..b0cb1497285838a9eada82fe0ac9a1f067a01426 100644 --- a/frontend/src/metabase-lib/lib/queries/utils/actions.js +++ b/frontend/src/metabase-lib/lib/queries/utils/actions.js @@ -1,8 +1,7 @@ import moment from "moment-timezone"; -import { isDate, isNumber } from "metabase/lib/schema_metadata"; - import { parseTimestamp } from "metabase/lib/time"; +import { isDate, isNumber } from "metabase-lib/lib/types/utils/isa"; import { rangeForValue, fieldRefForColumn, diff --git a/frontend/src/metabase-lib/lib/queries/utils/drilldown.js b/frontend/src/metabase-lib/lib/queries/utils/drilldown.js index 9b3617d0ffa5929e904d81757c5771dc7fb3857d..7194a1e1149aa1720ca35f121c89fc2bab889f3a 100644 --- a/frontend/src/metabase-lib/lib/queries/utils/drilldown.js +++ b/frontend/src/metabase-lib/lib/queries/utils/drilldown.js @@ -1,6 +1,11 @@ import _ from "underscore"; -import { isLatitude, isLongitude, isDate } from "metabase/lib/schema_metadata"; -import { isa } from "metabase-lib/lib/types/utils/isa"; + +import { + isa, + isLatitude, + isLongitude, + isDate, +} from "metabase-lib/lib/types/utils/isa"; import { TYPE } from "metabase-lib/lib/types/constants"; import { isExpressionField } from "metabase-lib/lib/queries/utils/field-ref"; diff --git a/frontend/src/metabase-lib/lib/queries/utils/filter.js b/frontend/src/metabase-lib/lib/queries/utils/filter.js index e84529ba503f17ac5bb18fb5dd223afb794c3797..c8c397320b622db8f7fe98ef788d5388fc41b9a0 100644 --- a/frontend/src/metabase-lib/lib/queries/utils/filter.js +++ b/frontend/src/metabase-lib/lib/queries/utils/filter.js @@ -4,7 +4,8 @@ import { FILTER_OPERATORS, isLiteral, } from "metabase/lib/expressions"; -import { STRING, getOperatorByTypeAndName } from "metabase/lib/schema_metadata"; +import { getOperatorByTypeAndName } from "metabase/lib/schema_metadata"; +import { STRING } from "metabase-lib/lib/types/constants"; import { isStartingFrom } from "metabase-lib/lib/queries/utils/query-time"; import { op, args, noNullValues, add, update, remove, clear } from "./util"; import { isValidField } from "./field-ref"; diff --git a/frontend/src/metabase-lib/lib/types/constants.js b/frontend/src/metabase-lib/lib/types/constants.js index b1b8c4a3bd1023ed6dd3945f60e1a73426a0c2c9..48b68a7db75018042ff03d325a5114b9863edf8b 100644 --- a/frontend/src/metabase-lib/lib/types/constants.js +++ b/frontend/src/metabase-lib/lib/types/constants.js @@ -1,3 +1,83 @@ import { TYPE as cljs_TYPE } from "cljs/metabase.types"; export const TYPE = cljs_TYPE; + +// primary field types used for picking operators, etc +export const NUMBER = "NUMBER"; +export const STRING = "STRING"; +export const STRING_LIKE = "STRING_LIKE"; +export const BOOLEAN = "BOOLEAN"; +export const TEMPORAL = "TEMPORAL"; +export const LOCATION = "LOCATION"; +export const COORDINATE = "COORDINATE"; +export const FOREIGN_KEY = "FOREIGN_KEY"; +export const PRIMARY_KEY = "PRIMARY_KEY"; + +// other types used for various purposes +export const ENTITY = "ENTITY"; +export const SUMMABLE = "SUMMABLE"; +export const SCOPE = "SCOPE"; +export const CATEGORY = "CATEGORY"; +export const DIMENSION = "DIMENSION"; + +export const UNKNOWN = "UNKNOWN"; + +// NOTE: be sure not to create cycles using the "other" types +export const TYPE_HIERARCHIES = { + [TEMPORAL]: { + base: [TYPE.Temporal], + effective: [TYPE.Temporal], + semantic: [TYPE.Temporal], + }, + [NUMBER]: { + base: [TYPE.Number], + effective: [TYPE.Number], + semantic: [TYPE.Number], + }, + [STRING]: { + base: [TYPE.Text], + effective: [TYPE.Text], + semantic: [TYPE.Text, TYPE.Category], + }, + [STRING_LIKE]: { + base: [TYPE.TextLike], + effective: [TYPE.TextLike], + }, + [BOOLEAN]: { + base: [TYPE.Boolean], + effective: [TYPE.Boolean], + }, + [COORDINATE]: { + semantic: [TYPE.Coordinate], + }, + [LOCATION]: { + semantic: [TYPE.Address], + }, + [ENTITY]: { + semantic: [TYPE.FK, TYPE.PK, TYPE.Name], + }, + [FOREIGN_KEY]: { + semantic: [TYPE.FK], + }, + [PRIMARY_KEY]: { + semantic: [TYPE.PK], + }, + [SUMMABLE]: { + include: [NUMBER], + exclude: [ENTITY, LOCATION, TEMPORAL], + }, + [SCOPE]: { + include: [NUMBER, TEMPORAL, CATEGORY, ENTITY, STRING], + exclude: [LOCATION], + }, + [CATEGORY]: { + base: [TYPE.Boolean], + effective: [TYPE.Boolean], + semantic: [TYPE.Category], + include: [LOCATION], + }, + // NOTE: this is defunct right now. see definition of isDimension below. + [DIMENSION]: { + include: [TEMPORAL, CATEGORY, ENTITY], + }, +}; diff --git a/frontend/src/metabase-lib/lib/types/utils/isa.js b/frontend/src/metabase-lib/lib/types/utils/isa.js index 47403d1ddba3672d4ce6c551c8e093b4ebbdee6d..e101423510053d6c2c3f9f9da399ea14ef5dae49 100644 --- a/frontend/src/metabase-lib/lib/types/utils/isa.js +++ b/frontend/src/metabase-lib/lib/types/utils/isa.js @@ -1,6 +1,21 @@ import { isa as cljs_isa } from "cljs/metabase.types"; -import { TYPE } from "metabase-lib/lib/types/constants"; +import { + TYPE, + TYPE_HIERARCHIES, + TEMPORAL, + LOCATION, + COORDINATE, + FOREIGN_KEY, + PRIMARY_KEY, + STRING, + STRING_LIKE, + NUMBER, + BOOLEAN, + SUMMABLE, + SCOPE, + CATEGORY, +} from "metabase-lib/lib/types/constants"; /** * Is x the same as, or a descendant type of, y? @@ -18,10 +33,178 @@ export const isa = (x, y) => cljs_isa(x, y); // this will also make it easier to tweak how these checks work in the future, // e.g. when we add an `is_pk` column and eliminate the PK semantic type we can just look for places that use isPK -export function isPK(type) { +export function isTypePK(type) { return isa(type, TYPE.PK); } -export function isFK(type) { +export function isTypeFK(type) { return isa(type, TYPE.FK); } + +export function isFieldType(type, field) { + if (!field) { + return false; + } + + const typeDefinition = TYPE_HIERARCHIES[type]; + // check to see if it belongs to any of the field types: + const props = field.effective_type + ? ["effective", "semantic"] + : ["base", "semantic"]; + for (const prop of props) { + const allowedTypes = typeDefinition[prop]; + if (!allowedTypes) { + continue; + } + + const fieldType = field[prop + "_type"]; + for (const allowedType of allowedTypes) { + if (isa(fieldType, allowedType)) { + return true; + } + } + } + + // recursively check to see if it's NOT another field type: + for (const excludedType of typeDefinition.exclude || []) { + if (isFieldType(excludedType, field)) { + return false; + } + } + + // recursively check to see if it's another field type: + for (const includedType of typeDefinition.include || []) { + if (isFieldType(includedType, field)) { + return true; + } + } + return false; +} + +export function getFieldType(field) { + // try more specific types first, then more generic types + for (const type of [ + TEMPORAL, + LOCATION, + COORDINATE, + FOREIGN_KEY, + PRIMARY_KEY, + STRING, + STRING_LIKE, + NUMBER, + BOOLEAN, + ]) { + if (isFieldType(type, field)) { + return type; + } + } +} + +export const isDate = isFieldType.bind(null, TEMPORAL); +export const isNumeric = isFieldType.bind(null, NUMBER); +export const isBoolean = isFieldType.bind(null, BOOLEAN); +export const isString = isFieldType.bind(null, STRING); +export const isSummable = isFieldType.bind(null, SUMMABLE); +export const isScope = isFieldType.bind(null, SCOPE); +export const isCategory = isFieldType.bind(null, CATEGORY); +export const isLocation = isFieldType.bind(null, LOCATION); + +export const isDimension = col => + col && col.source !== "aggregation" && !isDescription(col); +export const isMetric = col => + col && col.source !== "breakout" && isSummable(col); + +export const isFK = field => field && isTypeFK(field.semantic_type); +export const isPK = field => field && isTypePK(field.semantic_type); +export const isEntityName = field => + field && isa(field.semantic_type, TYPE.Name); + +export const isAny = col => true; + +export const isNumericBaseType = field => { + if (!field) { + return false; + } + if (field.effective_type) { + return isa(field.effective_type, TYPE.Number); + } else { + return isa(field.base_type, TYPE.Number); + } +}; + +export const isDateWithoutTime = field => { + if (!field) { + return false; + } + if (field.effective_type) { + return isa(field.effective_type, TYPE.Date); + } else { + return isa(field.base_type, TYPE.Date); + } +}; + +// ZipCode, ID, etc derive from Number but should not be formatted as numbers +export const isNumber = field => + field && + isNumericBaseType(field) && + (field.semantic_type == null || isa(field.semantic_type, TYPE.Number)); + +export const isBinnedNumber = field => isNumber(field) && !!field.binning_info; + +export const isTime = field => { + if (!field) { + return false; + } + if (field.effective_type) { + return isa(field.effective_type, TYPE.Time); + } else { + return isa(field.base_type, TYPE.Time); + } +}; + +export const isAddress = field => + field && isa(field.semantic_type, TYPE.Address); +export const isCity = field => field && isa(field.semantic_type, TYPE.City); +export const isState = field => field && isa(field.semantic_type, TYPE.State); +export const isZipCode = field => + field && isa(field.semantic_type, TYPE.ZipCode); +export const isCountry = field => + field && isa(field.semantic_type, TYPE.Country); +export const isCoordinate = field => + field && isa(field.semantic_type, TYPE.Coordinate); +export const isLatitude = field => + field && isa(field.semantic_type, TYPE.Latitude); +export const isLongitude = field => + field && isa(field.semantic_type, TYPE.Longitude); + +export const isCurrency = field => + field && isa(field.semantic_type, TYPE.Currency); + +export const isDescription = field => + field && isa(field.semantic_type, TYPE.Description); + +export const isComment = field => + field && isa(field.semantic_type, TYPE.Comment); + +export const isID = field => isFK(field) || isPK(field); + +export const isURL = field => field && isa(field.semantic_type, TYPE.URL); +export const isEmail = field => field && isa(field.semantic_type, TYPE.Email); +export const isAvatarURL = field => + field && isa(field.semantic_type, TYPE.AvatarURL); +export const isImageURL = field => + field && isa(field.semantic_type, TYPE.ImageURL); + +export function hasLatitudeAndLongitudeColumns(cols) { + let hasLatitude = false; + let hasLongitude = false; + for (const col of cols) { + if (isLatitude(col)) { + hasLatitude = true; + } + if (isLongitude(col)) { + hasLongitude = true; + } + } + return hasLatitude && hasLongitude; +} diff --git a/frontend/src/metabase-lib/lib/types/utils/isa.unit.spec.js b/frontend/src/metabase-lib/lib/types/utils/isa.unit.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..619efcf6324d4897c9eddbc60229961ef1f9816c --- /dev/null +++ b/frontend/src/metabase-lib/lib/types/utils/isa.unit.spec.js @@ -0,0 +1,101 @@ +import { getFieldType } from "metabase-lib/lib/types/utils/isa"; +import { + TYPE, + TEMPORAL, + STRING, + STRING_LIKE, + NUMBER, + BOOLEAN, + LOCATION, + COORDINATE, + PRIMARY_KEY, +} from "metabase-lib/lib/types/constants"; + +describe("isa", () => { + describe("getFieldType", () => { + it("should know a date", () => { + expect(getFieldType({ base_type: TYPE.Date })).toEqual(TEMPORAL); + expect(getFieldType({ base_type: TYPE.DateTime })).toEqual(TEMPORAL); + expect(getFieldType({ base_type: TYPE.Time })).toEqual(TEMPORAL); + expect(getFieldType({ effective_type: TYPE.Date })).toEqual(TEMPORAL); + expect(getFieldType({ effective_type: TYPE.DateTime })).toEqual(TEMPORAL); + expect(getFieldType({ effective_type: TYPE.Time })).toEqual(TEMPORAL); + }); + + it("should know a number", () => { + expect(getFieldType({ base_type: TYPE.BigInteger })).toEqual(NUMBER); + expect(getFieldType({ base_type: TYPE.Integer })).toEqual(NUMBER); + expect(getFieldType({ base_type: TYPE.Float })).toEqual(NUMBER); + expect(getFieldType({ base_type: TYPE.Decimal })).toEqual(NUMBER); + }); + + it("should know a string", () => { + expect(getFieldType({ base_type: TYPE.Text })).toEqual(STRING); + }); + + it("should know things that are types of strings", () => { + expect( + getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.Name }), + ).toEqual(STRING); + expect( + getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.Description }), + ).toEqual(STRING); + expect( + getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.UUID }), + ).toEqual(STRING); + expect( + getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.URL }), + ).toEqual(STRING); + }); + + it("should know a pk", () => { + expect( + getFieldType({ base_type: TYPE.Integer, semantic_type: TYPE.PK }), + ).toEqual(PRIMARY_KEY); + }); + + it("should know a bool", () => { + expect(getFieldType({ base_type: TYPE.Boolean })).toEqual(BOOLEAN); + }); + + it("should know a location", () => { + expect(getFieldType({ semantic_type: TYPE.City })).toEqual(LOCATION); + expect(getFieldType({ semantic_type: TYPE.Country })).toEqual(LOCATION); + }); + + it("should know a coordinate", () => { + expect(getFieldType({ semantic_type: TYPE.Latitude })).toEqual( + COORDINATE, + ); + expect(getFieldType({ semantic_type: TYPE.Longitude })).toEqual( + COORDINATE, + ); + }); + + describe("should know something that is string-like", () => { + it("TYPE.TextLike", () => { + expect(getFieldType({ base_type: TYPE.TextLike })).toEqual(STRING_LIKE); + }); + + it("TYPE.IPAddress", () => { + expect(getFieldType({ base_type: TYPE.IPAddress })).toEqual( + STRING_LIKE, + ); + }); + }); + + it("should still recognize some types as a string regardless of its base type", () => { + // TYPE.Float can occur in a field filter + expect( + getFieldType({ base_type: TYPE.Float, semantic_type: TYPE.Name }), + ).toEqual(STRING); + expect( + getFieldType({ base_type: TYPE.Float, semantic_type: TYPE.Category }), + ).toEqual(STRING); + }); + + it("should know what it doesn't know", () => { + expect(getFieldType({ base_type: "DERP DERP DERP" })).toEqual(undefined); + }); + }); +}); diff --git a/frontend/src/metabase/admin/datamodel/components/database/ColumnItem/ColumnItem.jsx b/frontend/src/metabase/admin/datamodel/components/database/ColumnItem/ColumnItem.jsx index ee3050bbbb3c9bcdd4fde11670df5b4fa986f1b2..2f96deaa6ff3ccf0abadbc267e6d70062429f97a 100644 --- a/frontend/src/metabase/admin/datamodel/components/database/ColumnItem/ColumnItem.jsx +++ b/frontend/src/metabase/admin/datamodel/components/database/ColumnItem/ColumnItem.jsx @@ -9,13 +9,12 @@ import cx from "classnames"; import Select, { Option } from "metabase/core/components/Select"; import Button from "metabase/core/components/Button"; import * as MetabaseCore from "metabase/lib/core"; -import { isCurrency } from "metabase/lib/schema_metadata"; import { getGlobalSettingsForColumn } from "metabase/visualizations/lib/settings/column"; import { currency } from "cljs/metabase.shared.util.currency"; import * as MetabaseAnalytics from "metabase/lib/analytics"; -import { isFK } from "metabase-lib/lib/types/utils/isa"; +import { isTypeFK, isCurrency } from "metabase-lib/lib/types/utils/isa"; import { getFieldRawName } from "../../../utils"; import { ColumnItemInput } from "./ColumnItem.styled"; @@ -114,7 +113,7 @@ export default withRouter(Column); const getFkFieldPlaceholder = (field, idfields) => { const hasIdFields = idfields?.length > 0; const isRestrictedFKTargedSelected = - isFK(field.semantic_type) && + isTypeFK(field.semantic_type) && field.fk_target_field_id != null && !idfields?.some(idField => idField.id === field.fk_target_field_id); @@ -153,7 +152,11 @@ export class SemanticTypeAndTargetPicker extends Component { const { field, updateField } = this.props; // If we are changing the field from a FK to something else, we should delete any FKs present - if (field.target && field.target.id != null && isFK(field.semantic_type)) { + if ( + field.target && + field.target.id != null && + isTypeFK(field.semantic_type) + ) { await updateField({ semantic_type, fk_target_field_id: null, @@ -203,7 +206,7 @@ export class SemanticTypeAndTargetPicker extends Component { ]; const hasIdFields = idfields?.length > 0; - const showFKTargetSelect = isFK(field.semantic_type); + const showFKTargetSelect = isTypeFK(field.semantic_type); const showCurrencyTypeSelect = isCurrency(field); // If all FK target fields are in the same schema (like `PUBLIC` for sample database) diff --git a/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx b/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx index 9a8e47a9d7093fc0e240f6fc4910e6f6f0196f0e..b1b808e1c2c40321dbca13e3e0135c02084953f8 100644 --- a/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx +++ b/frontend/src/metabase/admin/datamodel/containers/FieldApp.jsx @@ -34,12 +34,11 @@ import { getMetadata } from "metabase/selectors/metadata"; // LIB import { has_field_values_options } from "metabase/lib/core"; import { getGlobalSettingsForColumn } from "metabase/visualizations/lib/settings/column"; -import { isCurrency } from "metabase/lib/schema_metadata"; import Databases from "metabase/entities/databases"; import Tables from "metabase/entities/tables"; import Fields from "metabase/entities/fields"; -import { isFK } from "metabase-lib/lib/types/utils/isa"; +import { isTypeFK, isCurrency } from "metabase-lib/lib/types/utils/isa"; import { rescanFieldValues, discardFieldValues } from "../field"; import UpdateCachedFieldValues from "../components/UpdateCachedFieldValues"; import FieldRemapping from "../components/FieldRemapping"; @@ -298,7 +297,7 @@ const FieldGeneralPane = ({ /> </Section> - {!isFK(field.semantic_type) && is_coerceable(field.base_type) && ( + {!isTypeFK(field.semantic_type) && is_coerceable(field.base_type) && ( <Section> <SectionHeader title={t`Cast to a specific data type`} /> <Select diff --git a/frontend/src/metabase/lib/click-behavior.js b/frontend/src/metabase/lib/click-behavior.js index 23c68d91c74d63641e62e1effa938d468bb4ec4b..f76ac2c5d4e852b817c00da2d8ef46918a103674 100644 --- a/frontend/src/metabase/lib/click-behavior.js +++ b/frontend/src/metabase/lib/click-behavior.js @@ -2,7 +2,6 @@ import _ from "underscore"; import { getIn } from "icepick"; import { t, ngettext, msgid } from "ttag"; -import { isDate } from "metabase/lib/schema_metadata"; import { parseTimestamp } from "metabase/lib/time"; import { formatDateTimeForParameter } from "metabase/lib/formatting/date"; import { @@ -10,7 +9,7 @@ import { variableFilterForParameter, } from "metabase/parameters/utils/filters"; import { isValidImplicitActionClickBehavior } from "metabase/writeback/utils"; -import { isa } from "metabase-lib/lib/types/utils/isa"; +import { isa, isDate } from "metabase-lib/lib/types/utils/isa"; import { TYPE } from "metabase-lib/lib/types/constants"; import Question from "metabase-lib/lib/Question"; import TemplateTagVariable from "metabase-lib/lib/variables/TemplateTagVariable"; diff --git a/frontend/src/metabase/lib/formatting/date.tsx b/frontend/src/metabase/lib/formatting/date.tsx index 666bccdcbc491c5b128f97182a0698cd4a44e2f4..91055db30db2e18ebcbc68a0179e5c246ed694bf 100644 --- a/frontend/src/metabase/lib/formatting/date.tsx +++ b/frontend/src/metabase/lib/formatting/date.tsx @@ -2,8 +2,8 @@ import React from "react"; import moment, { Moment } from "moment-timezone"; import { parseTimestamp } from "metabase/lib/time"; -import { isDateWithoutTime } from "metabase/lib/schema_metadata"; import type { DatetimeUnit } from "metabase-types/api/query"; +import { isDateWithoutTime } from "metabase-lib/lib/types/utils/isa"; import { DEFAULT_DATE_STYLE, DEFAULT_TIME_STYLE, diff --git a/frontend/src/metabase/lib/formatting/geography.ts b/frontend/src/metabase/lib/formatting/geography.ts index 92511fbd9f563d201145d3ecc5120ab58794fd0e..a7faf2968cc4d4a521ccdbc5ef506284b7c461cf 100644 --- a/frontend/src/metabase/lib/formatting/geography.ts +++ b/frontend/src/metabase/lib/formatting/geography.ts @@ -1,7 +1,7 @@ import d3 from "d3"; -import { isLatitude, isLongitude } from "metabase/lib/schema_metadata"; import { decimalCount } from "metabase/visualizations/lib/numeric"; +import { isLatitude, isLongitude } from "metabase-lib/lib/types/utils/isa"; import { OptionsType } from "./types"; const DECIMAL_DEGREES_FORMATTER = d3.format(".08f"); diff --git a/frontend/src/metabase/lib/formatting/link.ts b/frontend/src/metabase/lib/formatting/link.ts index 74811d8f72cb1bd12aa891dc0707324dcb5e45bb..b3a85604c3ebc89bd2327948f7072af40d449402 100644 --- a/frontend/src/metabase/lib/formatting/link.ts +++ b/frontend/src/metabase/lib/formatting/link.ts @@ -1,7 +1,6 @@ -import { isDate } from "metabase/lib/schema_metadata"; - import { formatValue } from "metabase/lib/formatting"; import type { DatasetColumn } from "metabase-types/api/dataset"; +import { isDate } from "metabase-lib/lib/types/utils/isa"; import { formatDateTimeForParameter } from "./date"; interface TemplateForClickFormatFunctionParamsType { diff --git a/frontend/src/metabase/lib/formatting/url.tsx b/frontend/src/metabase/lib/formatting/url.tsx index 1440a2c06a10410187f51dedee958ecdb5683215..0d67dc1e37812bde4154e490b5e66be531fb018a 100644 --- a/frontend/src/metabase/lib/formatting/url.tsx +++ b/frontend/src/metabase/lib/formatting/url.tsx @@ -2,7 +2,7 @@ import React from "react"; import ExternalLink from "metabase/core/components/ExternalLink"; import { getDataFromClicked } from "metabase/lib/click-behavior"; -import { isURL } from "metabase/lib/schema_metadata"; +import { isURL } from "metabase-lib/lib/types/utils/isa"; import { renderLinkTextForClick, renderLinkURLForClick } from "./link"; import { formatValue, getRemappedValue } from "./value"; diff --git a/frontend/src/metabase/lib/formatting/value.tsx b/frontend/src/metabase/lib/formatting/value.tsx index 4eba69c08ce6059c158918ba45940bfc604b7c92..2f281974f40cbb860ccdc398dd8b0dd8a93ad590 100644 --- a/frontend/src/metabase/lib/formatting/value.tsx +++ b/frontend/src/metabase/lib/formatting/value.tsx @@ -8,6 +8,9 @@ import { clickBehaviorIsValid, getDataFromClicked, } from "metabase/lib/click-behavior"; +import { renderLinkTextForClick } from "metabase/lib/formatting/link"; +import { NULL_DISPLAY_VALUE, NULL_NUMERIC_VALUE } from "metabase/lib/constants"; +import { rangeForValue } from "metabase-lib/lib/queries/utils/dataset"; import { isBoolean, isCoordinate, @@ -16,10 +19,7 @@ import { isNumber, isTime, isURL, -} from "metabase/lib/schema_metadata"; -import { renderLinkTextForClick } from "metabase/lib/formatting/link"; -import { NULL_DISPLAY_VALUE, NULL_NUMERIC_VALUE } from "metabase/lib/constants"; -import { rangeForValue } from "metabase-lib/lib/queries/utils/dataset"; +} from "metabase-lib/lib/types/utils/isa"; import { formatEmail } from "./email"; import { formatTime } from "./time"; import { formatUrl } from "./url"; diff --git a/frontend/src/metabase/lib/schema_metadata.js b/frontend/src/metabase/lib/schema_metadata.js index ac4e2e3dc3b51e1025ac0284e5dcb74503a208ff..7099ca19b56dfddaa8c99f0cab56708a584eb93c 100644 --- a/frontend/src/metabase/lib/schema_metadata.js +++ b/frontend/src/metabase/lib/schema_metadata.js @@ -2,246 +2,28 @@ import _ from "underscore"; import { t } from "ttag"; import { field_semantic_types_map } from "metabase/lib/core"; import { - isa, - isFK as isTypeFK, - isPK as isTypePK, + isNumeric, + isDate, + isBoolean, + isScope, + isSummable, + getFieldType, + isFieldType, + isLongitude, } from "metabase-lib/lib/types/utils/isa"; -import { TYPE } from "metabase-lib/lib/types/constants"; - -// primary field types used for picking operators, etc -export const NUMBER = "NUMBER"; -export const STRING = "STRING"; -export const STRING_LIKE = "STRING_LIKE"; -export const BOOLEAN = "BOOLEAN"; -export const TEMPORAL = "TEMPORAL"; -export const LOCATION = "LOCATION"; -export const COORDINATE = "COORDINATE"; -export const FOREIGN_KEY = "FOREIGN_KEY"; -export const PRIMARY_KEY = "PRIMARY_KEY"; - -// other types used for various purporses -export const ENTITY = "ENTITY"; -export const SUMMABLE = "SUMMABLE"; -export const SCOPE = "SCOPE"; -export const CATEGORY = "CATEGORY"; -export const DIMENSION = "DIMENSION"; - -export const UNKNOWN = "UNKNOWN"; - -// define various type hierarchies -// NOTE: be sure not to create cycles using the "other" types -const TYPES = { - [TEMPORAL]: { - base: [TYPE.Temporal], - effective: [TYPE.Temporal], - semantic: [TYPE.Temporal], - }, - [NUMBER]: { - base: [TYPE.Number], - effective: [TYPE.Number], - semantic: [TYPE.Number], - }, - [STRING]: { - base: [TYPE.Text], - effective: [TYPE.Text], - semantic: [TYPE.Text, TYPE.Category], - }, - [STRING_LIKE]: { - base: [TYPE.TextLike], - effective: [TYPE.TextLike], - }, - [BOOLEAN]: { - base: [TYPE.Boolean], - effective: [TYPE.Boolean], - }, - [COORDINATE]: { - semantic: [TYPE.Coordinate], - }, - [LOCATION]: { - semantic: [TYPE.Address], - }, - [ENTITY]: { - semantic: [TYPE.FK, TYPE.PK, TYPE.Name], - }, - [FOREIGN_KEY]: { - semantic: [TYPE.FK], - }, - [PRIMARY_KEY]: { - semantic: [TYPE.PK], - }, - [SUMMABLE]: { - include: [NUMBER], - exclude: [ENTITY, LOCATION, TEMPORAL], - }, - [SCOPE]: { - include: [NUMBER, TEMPORAL, CATEGORY, ENTITY, STRING], - exclude: [LOCATION], - }, - [CATEGORY]: { - base: [TYPE.Boolean], - effective: [TYPE.Boolean], - semantic: [TYPE.Category], - include: [LOCATION], - }, - // NOTE: this is defunct right now. see definition of isDimension below. - [DIMENSION]: { - include: [TEMPORAL, CATEGORY, ENTITY], - }, -}; - -export function isFieldType(type, field) { - if (!field) { - return false; - } - - const typeDefinition = TYPES[type]; - // check to see if it belongs to any of the field types: - const props = field.effective_type - ? ["effective", "semantic"] - : ["base", "semantic"]; - for (const prop of props) { - const allowedTypes = typeDefinition[prop]; - if (!allowedTypes) { - continue; - } - - const fieldType = field[prop + "_type"]; - for (const allowedType of allowedTypes) { - if (isa(fieldType, allowedType)) { - return true; - } - } - } - - // recursively check to see if it's NOT another field type: - for (const excludedType of typeDefinition.exclude || []) { - if (isFieldType(excludedType, field)) { - return false; - } - } - - // recursively check to see if it's another field type: - for (const includedType of typeDefinition.include || []) { - if (isFieldType(includedType, field)) { - return true; - } - } - return false; -} - -export function getFieldType(field) { - // try more specific types first, then more generic types - for (const type of [ - TEMPORAL, - LOCATION, - COORDINATE, - FOREIGN_KEY, - PRIMARY_KEY, - STRING, - STRING_LIKE, - NUMBER, - BOOLEAN, - ]) { - if (isFieldType(type, field)) { - return type; - } - } -} - -export const isDate = isFieldType.bind(null, TEMPORAL); -export const isNumeric = isFieldType.bind(null, NUMBER); -export const isBoolean = isFieldType.bind(null, BOOLEAN); -export const isString = isFieldType.bind(null, STRING); -export const isSummable = isFieldType.bind(null, SUMMABLE); -export const isScope = isFieldType.bind(null, SCOPE); -export const isCategory = isFieldType.bind(null, CATEGORY); -export const isLocation = isFieldType.bind(null, LOCATION); - -export const isDimension = col => - col && col.source !== "aggregation" && !isDescription(col); -export const isMetric = col => - col && col.source !== "breakout" && isSummable(col); - -export const isFK = field => field && isTypeFK(field.semantic_type); -export const isPK = field => field && isTypePK(field.semantic_type); -export const isEntityName = field => - field && isa(field.semantic_type, TYPE.Name); - -export const isAny = col => true; - -export const isNumericBaseType = field => { - if (!field) { - return false; - } - if (field.effective_type) { - return isa(field.effective_type, TYPE.Number); - } else { - return isa(field.base_type, TYPE.Number); - } -}; - -export const isDateWithoutTime = field => { - if (!field) { - return false; - } - if (field.effective_type) { - return isa(field.effective_type, TYPE.Date); - } else { - return isa(field.base_type, TYPE.Date); - } -}; - -// ZipCode, ID, etc derive from Number but should not be formatted as numbers -export const isNumber = field => - field && - isNumericBaseType(field) && - (field.semantic_type == null || isa(field.semantic_type, TYPE.Number)); - -export const isBinnedNumber = field => isNumber(field) && !!field.binning_info; - -export const isTime = field => { - if (!field) { - return false; - } - if (field.effective_type) { - return isa(field.effective_type, TYPE.Time); - } else { - return isa(field.base_type, TYPE.Time); - } -}; - -export const isAddress = field => - field && isa(field.semantic_type, TYPE.Address); -export const isCity = field => field && isa(field.semantic_type, TYPE.City); -export const isState = field => field && isa(field.semantic_type, TYPE.State); -export const isZipCode = field => - field && isa(field.semantic_type, TYPE.ZipCode); -export const isCountry = field => - field && isa(field.semantic_type, TYPE.Country); -export const isCoordinate = field => - field && isa(field.semantic_type, TYPE.Coordinate); -export const isLatitude = field => - field && isa(field.semantic_type, TYPE.Latitude); -export const isLongitude = field => - field && isa(field.semantic_type, TYPE.Longitude); - -export const isCurrency = field => - field && isa(field.semantic_type, TYPE.Currency); - -export const isDescription = field => - field && isa(field.semantic_type, TYPE.Description); - -export const isComment = field => - field && isa(field.semantic_type, TYPE.Comment); - -export const isID = field => isFK(field) || isPK(field); - -export const isURL = field => field && isa(field.semantic_type, TYPE.URL); -export const isEmail = field => field && isa(field.semantic_type, TYPE.Email); -export const isAvatarURL = field => - field && isa(field.semantic_type, TYPE.AvatarURL); -export const isImageURL = field => - field && isa(field.semantic_type, TYPE.ImageURL); +import { + TYPE, + TEMPORAL, + LOCATION, + COORDINATE, + FOREIGN_KEY, + PRIMARY_KEY, + STRING, + STRING_LIKE, + NUMBER, + BOOLEAN, + UNKNOWN, +} from "metabase-lib/lib/types/constants"; // filter operator argument constructors: @@ -306,7 +88,7 @@ function equivalentArgument(field, table) { function longitudeFieldSelectArgument(field, table) { const values = table.fields - .filter(field => isa(field.semantic_type, TYPE.Longitude)) + .filter(field => isLongitude(field)) .map(field => ({ key: field.id, name: field.display_name, @@ -740,20 +522,6 @@ export function addValidOperatorsToFields(table) { return table; } -export function hasLatitudeAndLongitudeColumns(cols) { - let hasLatitude = false; - let hasLongitude = false; - for (const col of cols) { - if (isLatitude(col)) { - hasLatitude = true; - } - if (isLongitude(col)) { - hasLongitude = true; - } - } - return hasLatitude && hasLongitude; -} - export function foreignKeyCountsByOriginTable(fks) { if (fks === null || !Array.isArray(fks)) { return null; diff --git a/frontend/src/metabase/modes/components/drill/ObjectDetailDrill.jsx b/frontend/src/metabase/modes/components/drill/ObjectDetailDrill.jsx index 9308f2fc7edc55b3362aaa88f09376b72ed8316f..ffe185e333242041c2ee9aa23666b17df6842cdf 100644 --- a/frontend/src/metabase/modes/components/drill/ObjectDetailDrill.jsx +++ b/frontend/src/metabase/modes/components/drill/ObjectDetailDrill.jsx @@ -1,6 +1,6 @@ import { t } from "ttag"; -import { isFK, isPK } from "metabase/lib/schema_metadata"; import { zoomInRow } from "metabase/query_builder/actions"; +import { isFK, isPK } from "metabase-lib/lib/types/utils/isa"; function hasManyPKColumns(question) { const fields = question.isDataset() diff --git a/frontend/src/metabase/parameters/utils/operators.ts b/frontend/src/metabase/parameters/utils/operators.ts index 92c0d224ccca279ac2ab26d2b9087a5158e86550..290b3a89dbc4fdc87e8e893d8ca3024e2c696dca 100644 --- a/frontend/src/metabase/parameters/utils/operators.ts +++ b/frontend/src/metabase/parameters/utils/operators.ts @@ -3,10 +3,8 @@ import { UiParameter } from "metabase/parameters/types"; import { doesOperatorExist, getOperatorByTypeAndName, - NUMBER, - STRING, - PRIMARY_KEY, } from "metabase/lib/schema_metadata"; +import { NUMBER, STRING, PRIMARY_KEY } from "metabase-lib/lib/types/constants"; import { PARAMETER_OPERATOR_TYPES } from "../constants"; import { getParameterType, getParameterSubType } from "./parameter-type"; diff --git a/frontend/src/metabase/query_builder/components/DatasetEditor/DatasetFieldMetadataSidebar/DatasetFieldMetadataSidebar.jsx b/frontend/src/metabase/query_builder/components/DatasetEditor/DatasetFieldMetadataSidebar/DatasetFieldMetadataSidebar.jsx index a8747a2b94639820591922df2a218406634ab902..e591edbe851bedcb7f31b2da10163fe9e9207349 100644 --- a/frontend/src/metabase/query_builder/components/DatasetEditor/DatasetFieldMetadataSidebar/DatasetFieldMetadataSidebar.jsx +++ b/frontend/src/metabase/query_builder/components/DatasetEditor/DatasetFieldMetadataSidebar/DatasetFieldMetadataSidebar.jsx @@ -15,8 +15,7 @@ import { field_visibility_types, field_semantic_types, } from "metabase/lib/core"; -import { isFK, getSemanticTypeIcon } from "metabase/lib/schema_metadata"; - +import { getSemanticTypeIcon } from "metabase/lib/schema_metadata"; import RootForm from "metabase/containers/FormikForm"; import { usePrevious } from "metabase/hooks/use-previous"; @@ -26,6 +25,7 @@ import ColumnSettings, { } from "metabase/visualizations/components/ColumnSettings"; import { getGlobalSettingsForColumn } from "metabase/visualizations/lib/settings/column"; import { isSameField } from "metabase-lib/lib/queries/utils/field-ref"; +import { isFK } from "metabase-lib/lib/types/utils/isa"; import { EDITOR_TAB_INDEXES } from "../constants"; import MappedFieldPicker from "./MappedFieldPicker"; diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterItem/BulkFilterItem.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterItem/BulkFilterItem.tsx index fbe9ff944263f963a5f59ad2dbb298be236611bd..9dafd37114d15ed27a40dcfb302d0ef4c03f4321 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterItem/BulkFilterItem.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterItem/BulkFilterItem.tsx @@ -1,10 +1,14 @@ import React, { useMemo, useCallback } from "react"; -import { isBoolean, isString, isNumber } from "metabase/lib/schema_metadata"; import { BooleanPickerCheckbox } from "metabase/query_builder/components/filters/pickers/BooleanPicker"; import Filter from "metabase-lib/lib/queries/structured/Filter"; import Dimension from "metabase-lib/lib/Dimension"; import StructuredQuery from "metabase-lib/lib/queries/StructuredQuery"; +import { + isBoolean, + isString, + isNumber, +} from "metabase-lib/lib/types/utils/isa"; import { BulkFilterSelect } from "../BulkFilterSelect"; import { InlineCategoryPicker } from "../InlineCategoryPicker"; diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/utils.ts b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/utils.ts index 2dd4b7b672c4872a3d0474b7c5b00a14bcb101ec..a072818a77057a20e735b7c135836474cf33b2a3 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/utils.ts +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/utils.ts @@ -1,8 +1,6 @@ -import { isDate } from "metabase/lib/schema_metadata"; +import { isDate } from "metabase-lib/lib/types/utils/isa"; import { DimensionOption } from "metabase-lib/lib/queries/StructuredQuery"; -import { LONG_TEXT_MIN } from "metabase-lib/lib/metadata/Field"; - type PriorityMap = { [key: string]: number | undefined }; const fieldSortPriorities: PriorityMap = { diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx index ffb2bb58b401a38a3fc5e13874e41f55f71fbabf..0eeaaf8c15f8e551ab7d816be4494ddd4ef2e2be 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx @@ -1,9 +1,9 @@ import React, { useCallback, useMemo } from "react"; import { t } from "ttag"; -import { isBoolean, isDate } from "metabase/lib/schema_metadata"; import TippyPopoverWithTrigger from "metabase/components/PopoverWithTrigger/TippyPopoverWithTrigger"; import { DateShortcutOptions } from "metabase/query_builder/components/filters/pickers/DatePicker/DatePickerShortcutOptions"; +import { isBoolean, isDate } from "metabase-lib/lib/types/utils/isa"; import StructuredQuery, { SegmentOption, } from "metabase-lib/lib/queries/StructuredQuery"; diff --git a/frontend/src/metabase/query_builder/components/filters/modals/InlineValuePicker/utils.ts b/frontend/src/metabase/query_builder/components/filters/modals/InlineValuePicker/utils.ts index 5e3548a4eefa431fe3d3770af14a6adf35ffa1c2..c4a00f7829f0ce1eec67e10932f4eb8f875b4b07 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/InlineValuePicker/utils.ts +++ b/frontend/src/metabase/query_builder/components/filters/modals/InlineValuePicker/utils.ts @@ -1,4 +1,4 @@ -import { isString } from "metabase/lib/schema_metadata"; +import { isString } from "metabase-lib/lib/types/utils/isa"; import type Field from "metabase-lib/lib/metadata/Field"; import type Filter from "metabase-lib/lib/queries/structured/Filter"; diff --git a/frontend/src/metabase/query_builder/components/filters/pickers/DefaultPicker.jsx b/frontend/src/metabase/query_builder/components/filters/pickers/DefaultPicker.jsx index 210aacfcec31f9c8ede436effc6611bfbe35e2d0..e3eb4fe03e6ea5afc068b04001b286821eaffe9a 100644 --- a/frontend/src/metabase/query_builder/components/filters/pickers/DefaultPicker.jsx +++ b/frontend/src/metabase/query_builder/components/filters/pickers/DefaultPicker.jsx @@ -9,11 +9,11 @@ import FieldValuesWidget from "metabase/components/FieldValuesWidget"; import { getFilterArgumentFormatOptions, isFuzzyOperator, - isCurrency, } from "metabase/lib/schema_metadata"; import { getCurrencySymbol } from "metabase/lib/formatting"; +import { isCurrency } from "metabase-lib/lib/types/utils/isa"; import { keyForColumn } from "metabase-lib/lib/queries/utils/dataset"; import TextPicker from "./TextPicker"; import SelectPicker from "./SelectPicker"; diff --git a/frontend/src/metabase/query_builder/selectors.js b/frontend/src/metabase/query_builder/selectors.js index d97740e028722866c22e13eb43d4c8cea5450c8a..ba616f4fb6e24c1c256213fc75708fad059ec508 100644 --- a/frontend/src/metabase/query_builder/selectors.js +++ b/frontend/src/metabase/query_builder/selectors.js @@ -16,7 +16,6 @@ import { MetabaseApi } from "metabase/services"; import { getComputedSettingsForSeries } from "metabase/visualizations/lib/settings/visualization"; import { getCardUiParameters } from "metabase/parameters/utils/cards"; import { normalizeParameterValue } from "metabase/parameters/utils/parameter-values"; -import { isPK } from "metabase/lib/schema_metadata"; import { isAdHocModelQuestion } from "metabase/lib/data-modeling/utils"; @@ -36,6 +35,7 @@ import { import ObjectMode from "metabase/modes/components/modes/ObjectMode"; import { LOAD_COMPLETE_FAVICON } from "metabase/hoc/Favicon"; +import { isPK } from "metabase-lib/lib/types/utils/isa"; import Mode from "metabase-lib/lib/Mode"; import NativeQuery from "metabase-lib/lib/queries/NativeQuery"; import Question from "metabase-lib/lib/Question"; diff --git a/frontend/src/metabase/reference/components/Field.jsx b/frontend/src/metabase/reference/components/Field.jsx index 93748ced06065ccbff16efbe15dd177fe028cde2..a6981a5cbefbdbf9caac732e21354d5ba319d0fa 100644 --- a/frontend/src/metabase/reference/components/Field.jsx +++ b/frontend/src/metabase/reference/components/Field.jsx @@ -10,7 +10,7 @@ import * as MetabaseCore from "metabase/lib/core"; import S from "metabase/components/List.css"; import Select from "metabase/core/components/Select"; import Icon from "metabase/components/Icon"; -import { isFK } from "metabase-lib/lib/types/utils/isa"; +import { isTypeFK } from "metabase-lib/lib/types/utils/isa"; import F from "./Field.css"; const Field = ({ field, foreignKeys, url, icon, isEditing, formField }) => ( @@ -84,8 +84,8 @@ const Field = ({ field, foreignKeys, url, icon, isEditing, formField }) => ( <div className={cx(S.itemSubtitle, F.fieldSecondary, { mt1: true })}> <div className={F.fieldForeignKey}> {isEditing - ? (isFK(formField.semantic_type.value) || - (isFK(field.semantic_type) && + ? (isTypeFK(formField.semantic_type.value) || + (isTypeFK(field.semantic_type) && formField.semantic_type.value === undefined)) && ( <Select name={formField.fk_target_field_id.name} @@ -99,7 +99,7 @@ const Field = ({ field, foreignKeys, url, icon, isEditing, formField }) => ( optionValueFn={o => o.id} /> ) - : isFK(field.semantic_type) && ( + : isTypeFK(field.semantic_type) && ( <span> {getIn(foreignKeys, [field.fk_target_field_id, "name"])} </span> diff --git a/frontend/src/metabase/reference/components/FieldTypeDetail.jsx b/frontend/src/metabase/reference/components/FieldTypeDetail.jsx index a93e7fe651cba484fa86dc5794f93c7757a76655..774793641a65dc0000372261a8fe1e8de0596806 100644 --- a/frontend/src/metabase/reference/components/FieldTypeDetail.jsx +++ b/frontend/src/metabase/reference/components/FieldTypeDetail.jsx @@ -4,12 +4,11 @@ import cx from "classnames"; import { getIn } from "icepick"; import { t } from "ttag"; import * as MetabaseCore from "metabase/lib/core"; -import { isNumericBaseType } from "metabase/lib/schema_metadata"; import Select from "metabase/core/components/Select"; import D from "metabase/reference/components/Detail.css"; -import { isFK } from "metabase-lib/lib/types/utils/isa"; +import { isTypeFK, isNumericBaseType } from "metabase-lib/lib/types/utils/isa"; const FieldTypeDetail = ({ field, @@ -56,8 +55,8 @@ const FieldTypeDetail = ({ </span> <span className="ml4"> {isEditing - ? (isFK(fieldTypeFormField.value) || - (isFK(field.semantic_type) && + ? (isTypeFK(fieldTypeFormField.value) || + (isTypeFK(field.semantic_type) && fieldTypeFormField.value === undefined)) && ( <Select placeholder={t`Select a foreign key`} @@ -69,7 +68,7 @@ const FieldTypeDetail = ({ optionValueFn={o => o.id} /> ) - : isFK(field.semantic_type) && ( + : isTypeFK(field.semantic_type) && ( <span> {getIn(foreignKeys, [field.fk_target_field_id, "name"])} </span> diff --git a/frontend/src/metabase/reference/utils.js b/frontend/src/metabase/reference/utils.js index 872cdd12a855fd4289d8cb7f8a3d81b424f04928..2a2c16f8c4811c4e6bb57d759d05a669e640862e 100644 --- a/frontend/src/metabase/reference/utils.js +++ b/frontend/src/metabase/reference/utils.js @@ -3,7 +3,7 @@ import { assoc, assocIn, chain } from "icepick"; import { titleize, humanize } from "metabase/lib/formatting"; import { startNewCard } from "metabase/lib/card"; import * as Urls from "metabase/lib/urls"; -import { isPK } from "metabase-lib/lib/types/utils/isa"; +import { isTypePK } from "metabase-lib/lib/types/utils/isa"; export const idsToObjectMap = (ids, objects) => ids @@ -26,11 +26,12 @@ export const databaseToForeignKeys = database => // ignore tables without primary key .filter( table => - table && table.fields.find(field => isPK(field.semantic_type)), + table && table.fields.find(field => isTypePK(field.semantic_type)), ) .map(table => ({ table: table, - field: table && table.fields.find(field => isPK(field.semantic_type)), + field: + table && table.fields.find(field => isTypePK(field.semantic_type)), })) .map(({ table, field }) => ({ id: field.id, diff --git a/frontend/src/metabase/visualizations/components/ChoroplethMap.jsx b/frontend/src/metabase/visualizations/components/ChoroplethMap.jsx index 878c5393461f1775fe29b4080a262bb50962af65..02914d05118b1bbe3d6eb9d699aff3215c9234ef 100644 --- a/frontend/src/metabase/visualizations/components/ChoroplethMap.jsx +++ b/frontend/src/metabase/visualizations/components/ChoroplethMap.jsx @@ -7,7 +7,6 @@ import _ from "underscore"; import Color from "color"; import LoadingSpinner from "metabase/components/LoadingSpinner"; -import { isMetric, isString } from "metabase/lib/schema_metadata"; import { MinColumnsError } from "metabase/visualizations/lib/errors"; import MetabaseSettings from "metabase/lib/settings"; @@ -17,6 +16,7 @@ import { computeMinimalBounds, getCanonicalRowKey, } from "metabase/visualizations/lib/mapping"; +import { isMetric, isString } from "metabase-lib/lib/types/utils/isa"; import ChartWithLegend from "./ChartWithLegend"; import LegacyChoropleth from "./LegacyChoropleth"; import LeafletChoropleth from "./LeafletChoropleth"; diff --git a/frontend/src/metabase/visualizations/components/LeafletGridHeatMap.jsx b/frontend/src/metabase/visualizations/components/LeafletGridHeatMap.jsx index 82e9eec26df1d47265e3adc3a1a5b4a6c38cf215..517636376cad9c2d44397fe28e5649ba1a71b31e 100644 --- a/frontend/src/metabase/visualizations/components/LeafletGridHeatMap.jsx +++ b/frontend/src/metabase/visualizations/components/LeafletGridHeatMap.jsx @@ -3,7 +3,7 @@ import { t } from "ttag"; import d3 from "d3"; import { color } from "metabase/lib/colors"; -import { isNumeric, isMetric } from "metabase/lib/schema_metadata"; +import { isNumeric, isMetric } from "metabase-lib/lib/types/utils/isa"; import { rangeForValue } from "metabase-lib/lib/queries/utils/dataset"; import { computeNumericDataInverval } from "../lib/numeric"; import LeafletMap from "./LeafletMap"; diff --git a/frontend/src/metabase/visualizations/components/LeafletMarkerPinMap.jsx b/frontend/src/metabase/visualizations/components/LeafletMarkerPinMap.jsx index 2ed6a0ead8810818597a8763df7f23f4df66dfbf..748bfe2b511a8f60981fb1ed9c427ff3763fd460 100644 --- a/frontend/src/metabase/visualizations/components/LeafletMarkerPinMap.jsx +++ b/frontend/src/metabase/visualizations/components/LeafletMarkerPinMap.jsx @@ -1,7 +1,7 @@ import L from "leaflet"; import _ from "underscore"; -import { isPK } from "metabase/lib/schema_metadata"; +import { isPK } from "metabase-lib/lib/types/utils/isa"; import LeafletMap from "./LeafletMap"; diff --git a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx index 685d34d7225f5cd53b4f9d33a94b96f184e0f0f2..86f3c32d6ffea405a9772505eed5a544b8e072dc 100644 --- a/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx +++ b/frontend/src/metabase/visualizations/components/LineAreaBarChart.jsx @@ -9,12 +9,6 @@ import { iconPropTypes } from "metabase/components/Icon"; import "./LineAreaBarChart.css"; -import { - isNumeric, - isDate, - isDimension, - isMetric, -} from "metabase/lib/schema_metadata"; import { getFriendlyName, MAX_SERIES } from "metabase/visualizations/lib/utils"; import { addCSSRule } from "metabase/lib/dom"; import { formatValue } from "metabase/lib/formatting"; @@ -25,6 +19,20 @@ import { MinRowsError, ChartSettingsError, } from "metabase/visualizations/lib/errors"; +import { getAccentColors } from "metabase/lib/colors/groups"; +import { + isNumeric, + isDate, + isDimension, + isMetric, +} from "metabase-lib/lib/types/utils/isa"; + +import { + LineAreaBarChartRoot, + ChartLegendCaption, +} from "./LineAreaBarChart.styled"; +import LegendLayout from "./legend/LegendLayout"; +import CardRenderer from "./CardRenderer"; const MUTE_STYLE = "opacity: 0.25;"; for (let i = 0; i < MAX_SERIES; i++) { @@ -66,14 +74,6 @@ for (let i = 0; i < MAX_SERIES; i++) { addCSSRule(`.LineAreaBarChart.mute-${i} svg:not(.stacked) .row`, MUTE_STYLE); } -import { getAccentColors } from "metabase/lib/colors/groups"; -import { - LineAreaBarChartRoot, - ChartLegendCaption, -} from "./LineAreaBarChart.styled"; -import LegendLayout from "./legend/LegendLayout"; -import CardRenderer from "./CardRenderer"; - export default class LineAreaBarChart extends Component { static noHeader = true; static supportsSeries = true; diff --git a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx index 89bfae20a2fa055a2907503db07c385f90afe378..ee8a5b2251d03b793a81587370f3934dcd446800 100644 --- a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx +++ b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetail.tsx @@ -2,8 +2,6 @@ import React, { useState, useEffect, useCallback } from "react"; import { connect } from "react-redux"; import { t } from "ttag"; -import { isPK } from "metabase/lib/schema_metadata"; - import { State } from "metabase-types/store"; import type { ForeignKey, ConcreteTableId } from "metabase-types/api"; import { DatasetData } from "metabase-types/types/Dataset"; @@ -33,6 +31,7 @@ import { } from "metabase/query_builder/selectors"; import { columnSettings } from "metabase/visualizations/lib/settings/column"; import { isVirtualCardId } from "metabase/lib/saved-questions"; +import { isPK } from "metabase-lib/lib/types/utils/isa"; import Table from "metabase-lib/lib/metadata/Table"; import Question from "metabase-lib/lib/Question"; import { ObjectId, OnVisualizationClickType } from "./types"; diff --git a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetailsTable.tsx b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetailsTable.tsx index 5d382e6cd47ad307c7098b54ed2ca3a75c6c9837..ecb0ef65e4359310802aa5e0a164baf5c79ce257 100644 --- a/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetailsTable.tsx +++ b/frontend/src/metabase/visualizations/components/ObjectDetail/ObjectDetailsTable.tsx @@ -7,9 +7,8 @@ import { DatasetData } from "metabase-types/types/Dataset"; import ExpandableString from "metabase/query_builder/components/ExpandableString"; import EmptyState from "metabase/components/EmptyState"; -import { isID } from "metabase/lib/schema_metadata"; import { formatValue, formatColumn } from "metabase/lib/formatting"; -import { isa } from "metabase-lib/lib/types/utils/isa"; +import { isa, isID } from "metabase-lib/lib/types/utils/isa"; import { TYPE } from "metabase-lib/lib/types/constants"; import { OnVisualizationClickType } from "./types"; diff --git a/frontend/src/metabase/visualizations/components/ObjectDetail/utils.ts b/frontend/src/metabase/visualizations/components/ObjectDetail/utils.ts index 63c7e3d1a29fb1d711e5f607a2132a847f65c0f2..d2eca12bd59251d923da32a506a0cb35bbfe0ba8 100644 --- a/frontend/src/metabase/visualizations/components/ObjectDetail/utils.ts +++ b/frontend/src/metabase/visualizations/components/ObjectDetail/utils.ts @@ -2,9 +2,9 @@ import { t } from "ttag"; import _ from "underscore"; import { singularize } from "metabase/lib/formatting"; -import { isPK, isEntityName } from "metabase/lib/schema_metadata"; import { DatasetData, Column } from "metabase-types/types/Dataset"; +import { isPK, isEntityName } from "metabase-lib/lib/types/utils/isa"; import Question from "metabase-lib/lib/Question"; import Table from "metabase-lib/lib/metadata/Table"; diff --git a/frontend/src/metabase/visualizations/components/PinMap.jsx b/frontend/src/metabase/visualizations/components/PinMap.jsx index bc6d24ca4778b1ff88e4721025153209e2f7a317..d6cc662ac835a49432053a6e8706659d58e6059f 100644 --- a/frontend/src/metabase/visualizations/components/PinMap.jsx +++ b/frontend/src/metabase/visualizations/components/PinMap.jsx @@ -5,8 +5,8 @@ import _ from "underscore"; import cx from "classnames"; import d3 from "d3"; import L from "leaflet"; -import { hasLatitudeAndLongitudeColumns } from "metabase/lib/schema_metadata"; import { LatitudeLongitudeError } from "metabase/visualizations/lib/errors"; +import { hasLatitudeAndLongitudeColumns } from "metabase-lib/lib/types/utils/isa"; import LeafletMarkerPinMap from "./LeafletMarkerPinMap"; import LeafletTilePinMap from "./LeafletTilePinMap"; diff --git a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx index 66f32fc1fb263580f6576720589ab6123518628b..2457eb6bf5a8b052f38c9c3bc2f040186cf3d717 100644 --- a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx +++ b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx @@ -17,7 +17,6 @@ import Button from "metabase/core/components/Button"; import Tooltip from "metabase/components/Tooltip"; import { formatValue } from "metabase/lib/formatting"; -import { isID, isPK, isFK } from "metabase/lib/schema_metadata"; import { getTableCellClickedObject, getTableHeaderClickedObject, @@ -34,6 +33,7 @@ import ExplicitSize from "metabase/components/ExplicitSize"; import Ellipsified from "metabase/core/components/Ellipsified"; import DimensionInfoPopover from "metabase/components/MetadataInfo/DimensionInfoPopover"; +import { isID, isPK, isFK } from "metabase-lib/lib/types/utils/isa"; import { fieldRefForColumn } from "metabase-lib/lib/queries/utils/dataset"; import Dimension from "metabase-lib/lib/Dimension"; import { memoizeClass } from "metabase-lib/lib/utils"; diff --git a/frontend/src/metabase/visualizations/components/TableSimple/TableCell.jsx b/frontend/src/metabase/visualizations/components/TableSimple/TableCell.jsx index 4b16ccd1b61c9aa2e9bbbe9154bdf52903a2ff1a..84b17d19670c60c1d9f16b0242a3ef1d9e44a2b7 100644 --- a/frontend/src/metabase/visualizations/components/TableSimple/TableCell.jsx +++ b/frontend/src/metabase/visualizations/components/TableSimple/TableCell.jsx @@ -5,13 +5,13 @@ import cx from "classnames"; import ExternalLink from "metabase/core/components/ExternalLink"; import { formatValue } from "metabase/lib/formatting"; -import { isID, isFK } from "metabase/lib/schema_metadata"; import { getTableCellClickedObject, getTableClickedObjectRowData, isColumnRightAligned, } from "metabase/visualizations/lib/table"; import { getColumnExtent } from "metabase/visualizations/lib/utils"; +import { isID, isFK } from "metabase-lib/lib/types/utils/isa"; import MiniBar from "../MiniBar"; import { CellRoot, CellContent } from "./TableCell.styled"; diff --git a/frontend/src/metabase/visualizations/components/TableSimple/TableSimple.jsx b/frontend/src/metabase/visualizations/components/TableSimple/TableSimple.jsx index 658fe46eef837f6104980178712c0a95985c672c..a0e99a2782085b54fb4ba251ad96b03f3e7a545a 100644 --- a/frontend/src/metabase/visualizations/components/TableSimple/TableSimple.jsx +++ b/frontend/src/metabase/visualizations/components/TableSimple/TableSimple.jsx @@ -13,8 +13,8 @@ import ExplicitSize from "metabase/components/ExplicitSize"; import Ellipsified from "metabase/core/components/Ellipsified"; import { isPositiveInteger } from "metabase/lib/number"; -import { isID } from "metabase/lib/schema_metadata"; import { isColumnRightAligned } from "metabase/visualizations/lib/table"; +import { isID } from "metabase-lib/lib/types/utils/isa"; import TableCell from "./TableCell"; import TableFooter from "./TableFooter"; diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx index 00cf6bb71b7458732ad9a58970b185a889b34b57..35349814db672df26b66791af4c55b23a95c7709 100644 --- a/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx +++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingsTableFormatting.jsx @@ -26,7 +26,7 @@ import { } from "metabase/components/sortable"; import * as MetabaseAnalytics from "metabase/lib/analytics"; -import { isNumeric, isString } from "metabase/lib/schema_metadata"; +import { isNumeric, isString } from "metabase-lib/lib/types/utils/isa"; const NUMBER_OPERATOR_NAMES = { "<": t`is less than`, diff --git a/frontend/src/metabase/visualizations/lib/numeric.js b/frontend/src/metabase/visualizations/lib/numeric.js index 6d170eb42103954a9874ce899c955637beb9b935..e378177f9ecc62a0a103e0ff4dc9207854834f72 100644 --- a/frontend/src/metabase/visualizations/lib/numeric.js +++ b/frontend/src/metabase/visualizations/lib/numeric.js @@ -1,4 +1,4 @@ -import { isNumeric } from "metabase/lib/schema_metadata"; +import { isNumeric } from "metabase-lib/lib/types/utils/isa"; export function dimensionIsNumeric({ cols, rows }, i = 0) { if (isNumeric(cols[i])) { diff --git a/frontend/src/metabase/visualizations/lib/settings/column.js b/frontend/src/metabase/visualizations/lib/settings/column.js index 1965328f1f1b1dc5fc4f40844fc9f95fa99cc81a..d863644152c053c462f4b472142c23b82e170a0b 100644 --- a/frontend/src/metabase/visualizations/lib/settings/column.js +++ b/frontend/src/metabase/visualizations/lib/settings/column.js @@ -5,14 +5,6 @@ import _ from "underscore"; import ChartNestedSettingColumns from "metabase/visualizations/components/settings/ChartNestedSettingColumns"; -import { - isDate, - isNumber, - isCoordinate, - isCurrency, - isDateWithoutTime, -} from "metabase/lib/schema_metadata"; - // HACK: cyclical dependency causing errors in unit tests // import { getVisualizationRaw } from "metabase/visualizations"; function getVisualizationRaw(...args) { @@ -51,6 +43,13 @@ export function columnSettings({ } import MetabaseSettings from "metabase/lib/settings"; +import { + isDate, + isNumber, + isCoordinate, + isCurrency, + isDateWithoutTime, +} from "metabase-lib/lib/types/utils/isa"; import { keyForColumn } from "metabase-lib/lib/queries/utils/dataset"; import { nestedSettings } from "./nested"; diff --git a/frontend/src/metabase/visualizations/lib/settings/graph.js b/frontend/src/metabase/visualizations/lib/settings/graph.js index b2f9710c07f8fbd470a9b3ea3a6aad29eb3e35a9..317e9bcc9dcfb474301ef4093f421e62a05fd40c 100644 --- a/frontend/src/metabase/visualizations/lib/settings/graph.js +++ b/frontend/src/metabase/visualizations/lib/settings/graph.js @@ -1,11 +1,5 @@ import { t } from "ttag"; import _ from "underscore"; -import { - isDimension, - isMetric, - isNumeric, - isAny, -} from "metabase/lib/schema_metadata"; import { columnsAreValid, getFriendlyName, @@ -26,6 +20,12 @@ import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries"; import { getMaxMetricsSupported } from "metabase/visualizations"; import { ChartSettingOrderedSimple } from "metabase/visualizations/components/settings/ChartSettingOrderedSimple"; +import { + isDimension, + isMetric, + isNumeric, + isAny, +} from "metabase-lib/lib/types/utils/isa"; // NOTE: currently we don't consider any date extracts to be histgrams const HISTOGRAM_DATE_EXTRACTS = new Set([ diff --git a/frontend/src/metabase/visualizations/lib/settings/utils.js b/frontend/src/metabase/visualizations/lib/settings/utils.js index 6518e819bd7df0952bc1c022a4c849dbbe6d478c..95045b1e462770f6578e5fe85a293f1dbaea99a4 100644 --- a/frontend/src/metabase/visualizations/lib/settings/utils.js +++ b/frontend/src/metabase/visualizations/lib/settings/utils.js @@ -1,10 +1,10 @@ import _ from "underscore"; -import { isDimension, isMetric } from "metabase/lib/schema_metadata"; import { getFriendlyName, columnsAreValid, getDefaultDimensionAndMetric, } from "metabase/visualizations/lib/utils"; +import { isDimension, isMetric } from "metabase-lib/lib/types/utils/isa"; export function getOptionFromColumn(col) { return { diff --git a/frontend/src/metabase/visualizations/lib/table.js b/frontend/src/metabase/visualizations/lib/table.js index d2aac3831663ed6a0db316e5019f2de0aa2f9de2..d0f03a2de8cfd4b9923f78d257a432ff7d15d757 100644 --- a/frontend/src/metabase/visualizations/lib/table.js +++ b/frontend/src/metabase/visualizations/lib/table.js @@ -1,4 +1,4 @@ -import { isNumber, isCoordinate } from "metabase/lib/schema_metadata"; +import { isNumber, isCoordinate } from "metabase-lib/lib/types/utils/isa"; export function getTableClickedObjectRowData( [series], diff --git a/frontend/src/metabase/visualizations/lib/timeseries.js b/frontend/src/metabase/visualizations/lib/timeseries.js index 2d4108080a6f1af4540f7b7eb9ed2c7b2ae7f6de..5fc0958a48bf63f723ec19628cbc6475fef79afc 100644 --- a/frontend/src/metabase/visualizations/lib/timeseries.js +++ b/frontend/src/metabase/visualizations/lib/timeseries.js @@ -1,8 +1,8 @@ import moment from "moment-timezone"; import _ from "underscore"; -import { isDate } from "metabase/lib/schema_metadata"; import { parseTimestamp } from "metabase/lib/time"; +import { isDate } from "metabase-lib/lib/types/utils/isa"; import { unexpectedTimezoneWarning, multipleTimezoneWarning } from "./warnings"; diff --git a/frontend/src/metabase/visualizations/lib/utils.js b/frontend/src/metabase/visualizations/lib/utils.js index b96029c5ac11b000f0191419d4a8b6d0bb52c787..c947d993353b941127b6159003ab32f684677a68 100644 --- a/frontend/src/metabase/visualizations/lib/utils.js +++ b/frontend/src/metabase/visualizations/lib/utils.js @@ -3,7 +3,11 @@ import d3 from "d3"; import { t } from "ttag"; import crossfilter from "crossfilter"; -import { isDimension, isMetric, isDate } from "metabase/lib/schema_metadata"; +import { + isDimension, + isMetric, + isDate, +} from "metabase-lib/lib/types/utils/isa"; export const MAX_SERIES = 100; diff --git a/frontend/src/metabase/visualizations/visualizations/Gauge.jsx b/frontend/src/metabase/visualizations/visualizations/Gauge.jsx index 3eaecc9f00bed1399fc8f7578d50af0cc992ec58..3a320d1cb173bbdf1d7022fb8fca9d0ddb96ec77 100644 --- a/frontend/src/metabase/visualizations/visualizations/Gauge.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Gauge.jsx @@ -9,10 +9,10 @@ import _ from "underscore"; import { color } from "metabase/lib/colors"; import { formatValue } from "metabase/lib/formatting"; -import { isNumeric } from "metabase/lib/schema_metadata"; import { columnSettings } from "metabase/visualizations/lib/settings/column"; import ChartSettingGaugeSegments from "metabase/visualizations/components/settings/ChartSettingGaugeSegments"; +import { isNumeric } from "metabase-lib/lib/types/utils/isa"; import { GaugeArcPath } from "./Gauge.styled"; const MAX_WIDTH = 500; diff --git a/frontend/src/metabase/visualizations/visualizations/List.tsx b/frontend/src/metabase/visualizations/visualizations/List.tsx index 3326f10922d21fd8457f825f65bcc1e22b2e721a..3f39ffd090b606c0c2a771b9b8d2f8361a6e9370 100644 --- a/frontend/src/metabase/visualizations/visualizations/List.tsx +++ b/frontend/src/metabase/visualizations/visualizations/List.tsx @@ -3,13 +3,6 @@ import { t } from "ttag"; import _ from "lodash"; import { formatColumn } from "metabase/lib/formatting"; -import { - isNumber, - isURL, - isEmail, - isImageURL, - isAvatarURL, -} from "metabase/lib/schema_metadata"; import List from "metabase/visualizations/components/List/List"; import ChartSettingsListColumns from "metabase/visualizations/components/settings/ChartSettingsListColumns"; @@ -19,6 +12,13 @@ import { VisualizationSettings } from "metabase-types/api/card"; import { Column } from "metabase-types/types/Dataset"; import type { DatasetColumn } from "metabase-types/api/dataset"; import { Series, VisualizationProps } from "metabase-types/types/Visualization"; +import { + isNumber, + isURL, + isEmail, + isImageURL, + isAvatarURL, +} from "metabase-lib/lib/types/utils/isa"; function ListViz(props: VisualizationProps) { const { data, settings } = props; diff --git a/frontend/src/metabase/visualizations/visualizations/Map.jsx b/frontend/src/metabase/visualizations/visualizations/Map.jsx index 19915b521536083b2579ea781a3887fb7ca4ff3e..0ff79ab74881f29f42d5a5b19e11655da51ce8c9 100644 --- a/frontend/src/metabase/visualizations/visualizations/Map.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Map.jsx @@ -9,15 +9,6 @@ import Link from "metabase/core/components/Link"; import ExternalLink from "metabase/core/components/ExternalLink"; import Icon from "metabase/components/Icon"; -import { - isNumeric, - isLatitude, - isLongitude, - isMetric, - hasLatitudeAndLongitudeColumns, - isState, - isCountry, -} from "metabase/lib/schema_metadata"; import { isSameSeries } from "metabase/visualizations/lib/utils"; import { metricSetting, @@ -33,6 +24,15 @@ const PIN_MAP_TYPES = new Set(["pin", "heat", "grid"]); import { getAccentColors } from "metabase/lib/colors/groups"; import ColorRangeSelector from "metabase/core/components/ColorRangeSelector"; +import { + isNumeric, + isLatitude, + isLongitude, + isMetric, + hasLatitudeAndLongitudeColumns, + isState, + isCountry, +} from "metabase-lib/lib/types/utils/isa"; import LeafletGridHeatMap from "../components/LeafletGridHeatMap"; import PinMap from "../components/PinMap"; import ChoroplethMap, { diff --git a/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx b/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx index 267563e19582a71cd0438817dc9f1c0d03d38d94..7f0352f792ac038b9e767effe756648216923852 100644 --- a/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx +++ b/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx @@ -13,7 +13,6 @@ import ChartSettingsTableFormatting from "metabase/visualizations/components/set import Ellipsified from "metabase/core/components/Ellipsified"; import Icon from "metabase/components/Icon"; -import { isDimension } from "metabase/lib/schema_metadata"; import { COLLAPSED_ROWS_SETTING, COLUMN_SPLIT_SETTING, @@ -30,6 +29,7 @@ import { columnSettings } from "metabase/visualizations/lib/settings/column"; import { ChartSettingIconRadio } from "metabase/visualizations/components/settings/ChartSettingIconRadio"; import { PLUGIN_SELECTORS } from "metabase/plugins"; +import { isDimension } from "metabase-lib/lib/types/utils/isa"; import { PivotTableRoot, PivotTableCell, diff --git a/frontend/src/metabase/visualizations/visualizations/Progress.jsx b/frontend/src/metabase/visualizations/visualizations/Progress.jsx index e49156b246350a298c540ffcb2b7ad1636e76901..2521b727830148869bf44b1c3b32088469bf4b28 100644 --- a/frontend/src/metabase/visualizations/visualizations/Progress.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Progress.jsx @@ -6,12 +6,12 @@ import _ from "underscore"; import Color from "color"; import cx from "classnames"; import { formatValue } from "metabase/lib/formatting"; -import { isNumeric } from "metabase/lib/schema_metadata"; import Icon from "metabase/components/Icon"; import IconBorder from "metabase/components/IconBorder"; import { color } from "metabase/lib/colors"; import { columnSettings } from "metabase/visualizations/lib/settings/column"; +import { isNumeric } from "metabase-lib/lib/types/utils/isa"; const BORDER_RADIUS = 5; const MAX_BAR_HEIGHT = 65; diff --git a/frontend/src/metabase/visualizations/visualizations/SmartScalar.jsx b/frontend/src/metabase/visualizations/visualizations/SmartScalar.jsx index 5def33591ff812cb026b3556098cb509589eb41e..4c33a10894b4feeddd123be0863fd02ef991cd44 100644 --- a/frontend/src/metabase/visualizations/visualizations/SmartScalar.jsx +++ b/frontend/src/metabase/visualizations/visualizations/SmartScalar.jsx @@ -3,7 +3,6 @@ import React from "react"; import { t, jt } from "ttag"; import _ from "underscore"; -import { isDate } from "metabase/lib/schema_metadata"; import { formatNumber, formatValue } from "metabase/lib/formatting"; import { color } from "metabase/lib/colors"; @@ -16,6 +15,7 @@ import ScalarValue, { ScalarWrapper, ScalarTitle, } from "metabase/visualizations/components/ScalarValue"; +import { isDate } from "metabase-lib/lib/types/utils/isa"; import { formatBucketing } from "metabase-lib/lib/queries/utils/query-time"; import { diff --git a/frontend/src/metabase/visualizations/visualizations/Table.jsx b/frontend/src/metabase/visualizations/visualizations/Table.jsx index 93c2cb6c9376e4f97b27ccded30c4194ae11c7d5..ad7595d3a60c669a6cab61938bb707cde2c7e594 100644 --- a/frontend/src/metabase/visualizations/visualizations/Table.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Table.jsx @@ -10,6 +10,14 @@ import { getOptionFromColumn } from "metabase/visualizations/lib/settings/utils" import { getColumnCardinality } from "metabase/visualizations/lib/utils"; import { formatColumn } from "metabase/lib/formatting"; +import ChartSettingOrderedColumns from "metabase/visualizations/components/settings/ChartSettingOrderedColumns"; +import ChartSettingsTableFormatting, { + isFormattable, +} from "metabase/visualizations/components/settings/ChartSettingsTableFormatting"; + +import { makeCellBackgroundGetter } from "metabase/visualizations/lib/table_format"; +import { columnSettings } from "metabase/visualizations/lib/settings/column"; + import { isMetric, isDimension, @@ -18,15 +26,7 @@ import { isEmail, isImageURL, isAvatarURL, -} from "metabase/lib/schema_metadata"; - -import ChartSettingOrderedColumns from "metabase/visualizations/components/settings/ChartSettingOrderedColumns"; -import ChartSettingsTableFormatting, { - isFormattable, -} from "metabase/visualizations/components/settings/ChartSettingsTableFormatting"; - -import { makeCellBackgroundGetter } from "metabase/visualizations/lib/table_format"; -import { columnSettings } from "metabase/visualizations/lib/settings/column"; +} from "metabase-lib/lib/types/utils/isa"; import { findColumnIndexForColumnSetting } from "metabase-lib/lib/queries/utils/dataset"; import * as Q_DEPRECATED from "metabase-lib/lib/queries/utils"; diff --git a/frontend/test/metabase/lib/schema_metadata.unit.spec.js b/frontend/test/metabase/lib/schema_metadata.unit.spec.js index 9f5755f19328b9328d131d3bc3162081c796bff1..9a3bd65ab967f0fea8d72a75eb2b1a3ac81ecaa6 100644 --- a/frontend/test/metabase/lib/schema_metadata.unit.spec.js +++ b/frontend/test/metabase/lib/schema_metadata.unit.spec.js @@ -1,15 +1,5 @@ import _ from "underscore"; import { - getFieldType, - TEMPORAL, - STRING, - STRING_LIKE, - NUMBER, - BOOLEAN, - LOCATION, - COORDINATE, - PRIMARY_KEY, - FOREIGN_KEY, foreignKeyCountsByOriginTable, isEqualsOperator, doesOperatorExist, @@ -22,96 +12,15 @@ import { getSemanticTypeName, } from "metabase/lib/schema_metadata"; -import { TYPE } from "metabase-lib/lib/types/constants"; +import { + TYPE, + NUMBER, + COORDINATE, + PRIMARY_KEY, + FOREIGN_KEY, +} from "metabase-lib/lib/types/constants"; describe("schema_metadata", () => { - describe("getFieldType", () => { - it("should know a date", () => { - expect(getFieldType({ base_type: TYPE.Date })).toEqual(TEMPORAL); - expect(getFieldType({ base_type: TYPE.DateTime })).toEqual(TEMPORAL); - expect(getFieldType({ base_type: TYPE.Time })).toEqual(TEMPORAL); - expect(getFieldType({ effective_type: TYPE.Date })).toEqual(TEMPORAL); - expect(getFieldType({ effective_type: TYPE.DateTime })).toEqual(TEMPORAL); - expect(getFieldType({ effective_type: TYPE.Time })).toEqual(TEMPORAL); - }); - - it("should know a number", () => { - expect(getFieldType({ base_type: TYPE.BigInteger })).toEqual(NUMBER); - expect(getFieldType({ base_type: TYPE.Integer })).toEqual(NUMBER); - expect(getFieldType({ base_type: TYPE.Float })).toEqual(NUMBER); - expect(getFieldType({ base_type: TYPE.Decimal })).toEqual(NUMBER); - }); - - it("should know a string", () => { - expect(getFieldType({ base_type: TYPE.Text })).toEqual(STRING); - }); - - it("should know things that are types of strings", () => { - expect( - getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.Name }), - ).toEqual(STRING); - expect( - getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.Description }), - ).toEqual(STRING); - expect( - getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.UUID }), - ).toEqual(STRING); - expect( - getFieldType({ base_type: TYPE.Text, semantic_type: TYPE.URL }), - ).toEqual(STRING); - }); - - it("should know a pk", () => { - expect( - getFieldType({ base_type: TYPE.Integer, semantic_type: TYPE.PK }), - ).toEqual(PRIMARY_KEY); - }); - - it("should know a bool", () => { - expect(getFieldType({ base_type: TYPE.Boolean })).toEqual(BOOLEAN); - }); - - it("should know a location", () => { - expect(getFieldType({ semantic_type: TYPE.City })).toEqual(LOCATION); - expect(getFieldType({ semantic_type: TYPE.Country })).toEqual(LOCATION); - }); - - it("should know a coordinate", () => { - expect(getFieldType({ semantic_type: TYPE.Latitude })).toEqual( - COORDINATE, - ); - expect(getFieldType({ semantic_type: TYPE.Longitude })).toEqual( - COORDINATE, - ); - }); - - describe("should know something that is string-like", () => { - it("TYPE.TextLike", () => { - expect(getFieldType({ base_type: TYPE.TextLike })).toEqual(STRING_LIKE); - }); - - it("TYPE.IPAddress", () => { - expect(getFieldType({ base_type: TYPE.IPAddress })).toEqual( - STRING_LIKE, - ); - }); - }); - - it("should still recognize some types as a string regardless of its base type", () => { - // TYPE.Float can occur in a field filter - expect( - getFieldType({ base_type: TYPE.Float, semantic_type: TYPE.Name }), - ).toEqual(STRING); - expect( - getFieldType({ base_type: TYPE.Float, semantic_type: TYPE.Category }), - ).toEqual(STRING); - }); - - it("should know what it doesn't know", () => { - expect(getFieldType({ base_type: "DERP DERP DERP" })).toEqual(undefined); - }); - }); - describe("foreignKeyCountsByOriginTable", () => { it("should work with null input", () => { expect(foreignKeyCountsByOriginTable(null)).toEqual(null);