diff --git a/frontend/src/metabase/lib/core.js b/frontend/src/metabase/lib/core.js index bfb1c1062f6328856f4ed799b2b6b93382c0ff95..b9e8c53eb143a6afc945a6f5b3c245ca9a942b46 100644 --- a/frontend/src/metabase/lib/core.js +++ b/frontend/src/metabase/lib/core.js @@ -208,6 +208,21 @@ export const field_special_types = [ name: t`Deletion timestamp`, section: t`Date and Time`, }, + { + id: TYPE.UpdatedDate, + name: t`Updated date`, + section: t`Date and Time`, + }, + { + id: TYPE.UpdatedTime, + name: t`Updated time`, + section: t`Date and Time`, + }, + { + id: TYPE.UpdatedTimestamp, + name: t`Updated timestamp`, + section: t`Date and Time`, + }, { id: TYPE.JoinDate, name: t`Join date`, diff --git a/frontend/test/metabase-bootstrap.js b/frontend/test/metabase-bootstrap.js index 27cb3f8e7dbbe09b10622008b7d03ae0f9114638..4541b7798eb533ced966796b9bb0921dab0a03e9 100644 --- a/frontend/test/metabase-bootstrap.js +++ b/frontend/test/metabase-bootstrap.js @@ -47,6 +47,9 @@ window.MetabaseBootstrap = { "type/State": ["type/Category", "type/Address", "type/Text"], "type/CancelationDate": ["type/Date", "type/CancelationTimestamp"], "type/CancelationTime": ["type/Date", "type/CancelationTimestamp"], + "type/UpdatedDate": ["type/Date", "type/UpdatedTimestamp"], + "type/UpdatedTime": ["type/Date", "type/UpdatedTimestamp"], + "type/UpdatedTimestamp": ["type/DateTime"], "type/DeletionDate": ["type/Date", "type/DeletionTimestamp"], "type/DateTimeWithZoneID": ["type/DateTimeWithTZ"], "type/Address": ["type/*"], diff --git a/src/metabase/sync/analyze/classifiers/name.clj b/src/metabase/sync/analyze/classifiers/name.clj index ae8a73aa3dcd518eebf1bb3793b2d67b25510384..bafe4ffb1b683e026f63f2273f50d7c35e6ead5a 100644 --- a/src/metabase/sync/analyze/classifiers/name.clj +++ b/src/metabase/sync/analyze/classifiers/name.clj @@ -83,6 +83,9 @@ [#"delet(?:e|i)" date-type :type/DeletionDate] [#"delet(?:e|i)" time-type :type/DeletionTime] [#"delet(?:e|i)" timestamp-type :type/DeletionTimestamp] + [#"update" date-type :type/UpdatedDate] + [#"update" time-type :type/UpdatedTime] + [#"update" timestamp-type :type/UpdatedTimestamp] [#"source" int-or-text-type :type/Source] [#"channel" int-or-text-type :type/Source] [#"share" float-type :type/Share] diff --git a/src/metabase/types.clj b/src/metabase/types.clj index 397c08a62b78baca837c981245a2e9e55919c9d3..e5d253d4a752f24c1880b72aa2a2578f0b4f239b 100644 --- a/src/metabase/types.clj +++ b/src/metabase/types.clj @@ -134,6 +134,12 @@ (derive :type/DeletionDate :type/Date) (derive :type/DeletionDate :type/DeletionTimestamp) +(derive :type/UpdatedTimestamp :type/DateTime) +(derive :type/UpdatedTime :type/Date) +(derive :type/UpdatedTime :type/UpdatedTimestamp) +(derive :type/UpdatedDate :type/Date) +(derive :type/UpdatedDate :type/UpdatedTimestamp) + (derive :type/Birthdate :type/Date) diff --git a/test/metabase/sync/analyze/classifiers/name_test.clj b/test/metabase/sync/analyze/classifiers/name_test.clj index 0a77c0e04b283e6f4cd10cda01829cbc988c81ba..a0eef614bef97dacffd7e17dd8c3ed4202aa5e71 100644 --- a/test/metabase/sync/analyze/classifiers/name_test.clj +++ b/test/metabase/sync/analyze/classifiers/name_test.clj @@ -46,6 +46,16 @@ :type/Name ["first_name"] :type/Name ["name"] :type/Quantity ["quantity" :type/Integer])) + (testing "name and type matches" + (testing "matches \"updated at\" style columns" + (let [classify (fn [table-name table-type] (-> {:name table-name :base_type table-type} + table/map->TableInstance + classify.names/infer-special-type))] + (doseq [[col-type expected] [[:type/Date :type/UpdatedDate] + [:type/DateTime :type/UpdatedTimestamp] + [:type/Time :type/UpdatedTime]]] + (doseq [column-name ["updated_at" "updated" "updated-at"]] + (is (= expected (classify column-name col-type)))))))) (testing "Doesn't mark state columns (#2735)" (doseq [column-name ["state" "order_state" "state_of_order"]] (is (not= :type/State (infer column-name)))))))