From dc4d4de2c4629b5cf0c9d28e9750c6a910fb0e6a Mon Sep 17 00:00:00 2001
From: dpsutton <dan@dpsutton.com>
Date: Wed, 18 Nov 2020 13:18:38 -0600
Subject: [PATCH] Add `updated` special type for timestamps (#13818)

keyed off of column names that include "update" which are date, time,
or datetime columns.
---
 frontend/src/metabase/lib/core.js                 | 15 +++++++++++++++
 frontend/test/metabase-bootstrap.js               |  3 +++
 src/metabase/sync/analyze/classifiers/name.clj    |  3 +++
 src/metabase/types.clj                            |  6 ++++++
 .../sync/analyze/classifiers/name_test.clj        | 10 ++++++++++
 5 files changed, 37 insertions(+)

diff --git a/frontend/src/metabase/lib/core.js b/frontend/src/metabase/lib/core.js
index bfb1c1062f6..b9e8c53eb14 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 27cb3f8e7db..4541b7798eb 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 ae8a73aa3dc..bafe4ffb1b6 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 397c08a62b7..e5d253d4a75 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 0a77c0e04b2..a0eef614bef 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)))))))
-- 
GitLab