Skip to content
Snippets Groups Projects
Unverified Commit ba581fa6 authored by Cal Herries's avatar Cal Herries Committed by GitHub
Browse files

datetime-diff function for MongoDB (#27042)


* Fix mongo version checking for now

* Add minor versions for comparison

* Handle nil case

* newline

* Replace _

* Use dbms-version semantic-version instead

* Compare only the major and minor version

* Fix mongo database-supports?

* Fix duplicate require

* Fix typo

* Remove expressions from version check

* Fix various mongo expressions

`trim`, `rtrim`, `ltrim` needed to be wrapped in `{"input" expr}` object
`replace` needed to be wrapped in `{"input" expr "find" ...
"replacement" ...}' object
`substring` needed to fill in the 3rd argument, optional in mbql but
required in mongo. Also to use a 1 based index

* Generalize semantic-version-gte

* Used synced dbms_version for testing feature support

* Expressions are only supported by mongo 4.2+

* Disable some tests

* Fix mongo division

Handle nulls with an upfront condition check.
Handle multiple divisors.

* Remove unused namespace

* Throw exeception if using replace on mongo < 4.4

* Skip test because of #27249

* Move minimum Mongo CI version to 4.2

* Fix sorting by expressions

$sort needs to come before $project otherwise we can only see the
projected fields, however expressions are only added in $project.

So now if a sort includes an expression, we will use $addFields to be
able to sort by that expression.

* Disable tests for expressions inside aggregations

To be addressed by #27275

* Handle aggregation nested in an expression

* Remove :truncation-start workaround

* Enable tests for expressions inside aggregations

* Fix datetime-math-tests

* Make sure dbms_version is included when fetching database for store

* Update doc for replace to indicate it should replace all occurrences

* Add mongo datetime-diff

* Fix database-supports?

* Fix order-by-test

* Handle embedded special aggregations (#27315)

* Handle embedded special aggregations
* Preserve aggregation options for nested aggregations
* Use top-level aggregation name as group name

* Disable nil punning on semantic version check (#27317)

* Remove nil punning from database-supports?

* Formatting

* Refactor based on Tamas' suggestions

* Change datetime-diff from case statement to multimethod

Co-authored-by: default avatarCase Nelson <case@metabase.com>
Co-authored-by: default avatarTamás Benkő <tamas@metabase.com>
Co-authored-by: default avatarmetamben <103100869+metamben@users.noreply.github.com>
parent 6d7f778e
No related branches found
No related tags found
No related merge requests found
......@@ -246,6 +246,12 @@
:semantic-version
(driver.u/semantic-version-gte [5])))
(defmethod driver/database-supports? [:mongo :datetime-diff]
[_driver _feature db]
(-> (:dbms_version db)
:semantic-version
(driver.u/semantic-version-gte [5])))
(defmethod driver/database-supports? [:mongo :now]
;; The $$NOW aggregation expression was introduced in version 4.2.
[_driver _feature db]
......
......@@ -559,6 +559,55 @@
:unit unit
:amount amount}})
(defmulti datetime-diff
"Helper function for ->rvalue for `datetime-diff` clauses."
{:arglists '([x y unit])}
(fn [_ _ unit] unit))
(defmethod datetime-diff :year
[x y _unit]
{$divide [(datetime-diff x y :month) 12]})
(defmethod datetime-diff :quarter
[x y _unit]
{$divide [(datetime-diff x y :month) 3]})
(defmethod datetime-diff :month
[x y _unit]
{$add [{"$dateDiff" {:startDate x, :endDate y, :unit "month"}}
;; dateDiff counts month boundaries not whole months, so we need to adjust
;; if x<y but x>y in the month calendar then subtract one month
;; if x>y but x<y in the month calendar then add one month
{:$switch {:branches [{:case {:$and [{$lt [x y]}
{$gt [{$dayOfMonth x} {$dayOfMonth y}]}]}
:then -1}
{:case {:$and [{$gt [x y]}
{$lt [{$dayOfMonth x} {$dayOfMonth y}]}]}
:then 1}]
:default 0}}]})
(defmethod datetime-diff :week
[x y _unit]
{$divide [(datetime-diff x y :day) 7]})
(defn- simple-datediff
[x y unit]
{"$dateDiff" {:startDate x, :endDate y, :unit unit}})
(defmethod datetime-diff :day [x y unit] (simple-datediff x y unit))
(defmethod datetime-diff :minute [x y unit] (simple-datediff x y unit))
(defmethod datetime-diff :second [x y unit] (simple-datediff x y unit))
(defmethod datetime-diff :hour
[x y _unit]
;; mongo's dateDiff with hour isn't accurate to the millisecond
{$divide [{"$dateDiff" {:startDate x, :endDate y, :unit "millisecond"}}
3600000]})
(defmethod ->rvalue :datetime-diff [[_ x y unit]]
(check-date-operations-supported)
(datetime-diff (->rvalue x) (->rvalue y) unit))
;;; +----------------------------------------------------------------------------------------------------------------+
;;; | CLAUSE APPLICATION |
;;; +----------------------------------------------------------------------------------------------------------------+
......
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