Skip to content
Snippets Groups Projects
Unverified Commit 4dd50562 authored by Ngoc Khuat's avatar Ngoc Khuat Committed by GitHub
Browse files

fix mongo not able to filter by UUID (#26367)

parent e2939bf6
No related branches found
No related tags found
No related merge requests found
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
$multiply $ne $not $or $project $regex $second $size $skip $sort $strcasecmp $subtract $multiply $ne $not $or $project $regex $second $size $skip $sort $strcasecmp $subtract
$sum $toLower $year]] $sum $toLower $year]]
[schema.core :as s]) [schema.core :as s])
(:import org.bson.types.ObjectId)) (:import [org.bson.types ObjectId Binary]
org.bson.BsonBinarySubType))
;;; +----------------------------------------------------------------------------------------------------------------+ ;;; +----------------------------------------------------------------------------------------------------------------+
;;; | Schema | ;;; | Schema |
...@@ -289,15 +290,32 @@ ...@@ -289,15 +290,32 @@
(defmethod ->rvalue nil [_] nil) (defmethod ->rvalue nil [_] nil)
(defn- uuid->bsonbinary
[u]
(let [lo (.getLeastSignificantBits ^java.util.UUID u)
hi (.getMostSignificantBits ^java.util.UUID u)
ba (-> (java.nio.ByteBuffer/allocate 16) ; UUID is 128 bits-long
(.putLong hi)
(.putLong lo)
(.array))]
(Binary. BsonBinarySubType/UUID_STANDARD ba)))
(defmethod ->rvalue :value (defmethod ->rvalue :value
[[_ value {base-type :base_type}]] [[_ value {base-type :base_type}]]
(if (and (isa? base-type :type/MongoBSONID) (cond
(some? value)) ;; Passing nil or "" to the ObjectId or Binary constructor throws an exception
;; Passing nil or "" to the ObjectId constructor throws an exception (or (nil? value) (= value ""))
;; "invalid hexadecimal representation of an ObjectId: []" so, just treat it as nil value
(when (not= value "")
(ObjectId. (str value))) (isa? base-type :type/MongoBSONID)
value)) (ObjectId. (str value))
(isa? base-type :type/UUID)
(-> (str value)
java.util.UUID/fromString
uuid->bsonbinary)
:else value))
(defn- $date-from-string [s] (defn- $date-from-string [s]
{:$dateFromString {:dateString (str s)}}) {:$dateFromString {:dateString (str s)}})
......
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
:dbname "metabase-test" :dbname "metabase-test"
:version "2.2134234.lol"} :version "2.2134234.lol"}
:expected false}] :expected false}]
:let [ssl-details (tdm/conn-details details)]] :let [ssl-details (tdm/conn-details details)]]
(testing (str "connect with " details) (testing (str "connect with " details)
(is (= expected (is (= expected
(let [db (db/insert! Database {:name "dummy", :engine "mongo", :details ssl-details})] (let [db (db/insert! Database {:name "dummy", :engine "mongo", :details ssl-details})]
...@@ -264,42 +264,71 @@ ...@@ -264,42 +264,71 @@
{:order-by [:name]})] {:order-by [:name]})]
(into {} field)))))))))) (into {} field))))))))))
(tx/defdataset with-bson-ids (tx/defdataset with-bson-ids
[["birds" [["birds"
[{:field-name "name", :base-type :type/Text} [{:field-name "name", :base-type :type/Text}
{:field-name "bird_id", :base-type :type/MongoBSONID}] {:field-name "bird_id", :base-type :type/MongoBSONID}
[["Rasta Toucan" (ObjectId. "012345678901234567890123")] {:field-name "bird_uuid", :base-type :type/UUID}]
["Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")] [["Rasta Toucan" (ObjectId. "012345678901234567890123") "11111111-1111-1111-1111-111111111111"]
["Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef") "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"]
["Unlucky Raven" nil]]]]) ["Unlucky Raven" nil]]]])
(deftest bson-ids-test (deftest bson-ids-test
(mt/test-driver :mongo (mt/test-driver :mongo
(testing "BSON IDs" (mt/dataset with-bson-ids
(is (= [[2 "Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")]] (testing "BSON IDs"
(rows (mt/dataset with-bson-ids (testing "Check that we support Mongo BSON ID and can filter by it (#1367)"
(mt/run-mbql-query birds (is (= [[2 "Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")]]
{:filter [:= $bird_id "abcdefabcdefabcdefabcdef"]})))) (rows (mt/run-mbql-query birds
"Check that we support Mongo BSON ID and can filter by it (#1367)") {:filter [:= $bird_id "abcdefabcdefabcdefabcdef"]
:fields [$id $name $bird_id]})))))
(is (= [[3 "Unlucky Raven" nil]]
(rows (mt/dataset with-bson-ids (testing "handle null ObjectId queries properly (#11134)"
(mt/run-mbql-query birds (is (= [[3 "Unlucky Raven" nil]]
{:filter [:is-null $bird_id]})))) (rows (mt/run-mbql-query birds
"handle null ObjectId queries properly (#11134)") {:filter [:is-null $bird_id]
:fields [$id $name $bird_id]})))))
(is (= [[3 "Unlucky Raven" nil]]
(rows (mt/dataset with-bson-ids (testing "treat null ObjectId as empty (#15801)"
(mt/run-mbql-query birds (is (= [[3 "Unlucky Raven" nil]]
{:filter [:is-empty $bird_id]})))) (rows (mt/run-mbql-query birds
"treat null ObjectId as empty (#15801)") {:filter [:is-empty $bird_id]
:fields [$id $name $bird_id]})))))
(is (= [[1 "Rasta Toucan" (ObjectId. "012345678901234567890123")]
[2 "Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")]] (testing "treat non-null ObjectId as not-empty (#15801)"
(rows (mt/dataset with-bson-ids (is (= [[1 "Rasta Toucan" (ObjectId. "012345678901234567890123")]
(mt/run-mbql-query birds [2 "Lucky Pigeon" (ObjectId. "abcdefabcdefabcdefabcdef")]]
{:filter [:not-empty $bird_id]})))) (rows (mt/run-mbql-query birds
"treat non-null ObjectId as not-empty (#15801)")))) {:filter [:not-empty $bird_id]
:fields [$id $name $bird_id]}))))))
(testing "BSON UUIDs"
(testing "Check that we support Mongo BSON UUID and can filter by it"
(is (= [[2 "Lucky Pigeon" "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"]]
(rows (mt/run-mbql-query birds
{:filter [:= $bird_uuid "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"]
:fields [$id $name $bird_uuid]})))))
(testing "handle null UUID queries properly"
(is (= [[3 "Unlucky Raven" nil]]
(rows (mt/run-mbql-query birds
{:filter [:is-null $bird_uuid]
:fields [$id $name $bird_uuid]})))))
(testing "treat null UUID as empty"
(is (= [[3 "Unlucky Raven" nil]]
(rows (mt/run-mbql-query birds
{:filter [:is-empty $bird_uuid]
:fields [$id $name $bird_uuid]}))))))
(testing "treat non-null UUID as not-empty"
(is (= [[1 "Rasta Toucan" "11111111-1111-1111-1111-111111111111"]
[2 "Lucky Pigeon" "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"]]
(rows (mt/run-mbql-query birds
{:filter [:not-empty $bird_uuid]
:fields [$id $name $bird_uuid]}))))))))
(deftest bson-fn-call-forms-test (deftest bson-fn-call-forms-test
(mt/test-driver :mongo (mt/test-driver :mongo
......
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