Compare commits

...

18 commits

Author SHA1 Message Date
George Narroway
0930cbbcf0 bump version to 0.9.0-SNAPSHOT 2024-02-07 11:11:01 +08:00
George Narroway
c39dd281c4 version 0.8.0 release 2024-02-07 11:09:44 +08:00
George Narroway
0acd78c963 bump dev dependencies 2024-02-07 11:08:43 +08:00
George Narroway
7e62bf8898 add test and readme for realise-fn 2024-02-07 11:07:55 +08:00
gnarroway
9c2c899876
Merge pull request #10 from jimpil/master
various optimisations/fixes
2024-02-07 10:44:13 +08:00
George Narroway
28e054aa3f creating existing collection no longer throws 2024-02-07 10:41:52 +08:00
George Narroway
57f2115e7b bump version 2024-02-07 10:41:38 +08:00
jimpil
1de8cabb5b type-hint all arities of mongo-id 2024-01-17 23:09:05 +00:00
jimpil
4ffb3f8a9a simplify data-literals 2024-01-17 23:05:35 +00:00
jimpil
fad49204e1 remove redundant require 2024-01-17 22:14:40 +00:00
jimpil
c09581a587 improve mongo-id 2024-01-17 22:03:06 +00:00
jimpil
3ac5a5cf69 remove lsp/clj-kondo folders 2024-01-17 21:40:45 +00:00
jimpil
6e8dc539ea update gitignore file 2024-01-17 21:36:14 +00:00
jimpil
11dfeabf17 various fixes - 2 2024-01-17 21:31:51 +00:00
jimpil
b32f13574a various optimisations/fixes 2024-01-17 21:23:40 +00:00
George Narroway
3934a6cc50 0.7.0 release again 2022-10-04 19:25:28 +08:00
George Narroway
c46e114f44 dependency update 2022-10-04 19:24:03 +08:00
George Narroway
46ca9d63df version 0.7.0 release 2022-10-04 19:12:29 +08:00
11 changed files with 177 additions and 102 deletions

2
.gitignore vendored
View file

@ -9,3 +9,5 @@ pom.xml.asc
/.nrepl-port
.hgignore
.hg/
.lsp/
.clj-kondo/

View file

@ -1,9 +1,18 @@
# Change Log
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
## Unreleased
## 0.8.0 - 2024-02-07
### Added
- Support for passing `:realise-fn` to avoid lazy response (thanks @jimpil)
### Changed
- Remove reflective calls
## 0.7.0 - 2022-10-04
### Added
- Support reading dates as instances (thanks @henryw374)
- Support reading dates as instanceres (thanks @henryw374)
- Support data literal for mongo id (thanks @henryw374)
- Support for implicit transactions (thanks @AdamClements)
- Support for aggregation pipeline in find-one-and-update (requires 4.2+, thanks @jacobemcken)

View file

@ -32,10 +32,10 @@ For Leinengen, add this to your project.clj:
```clojure
;; The underlying driver -- any newer version can also be used
[org.mongodb/mongodb-driver-sync "4.7.1"]
[org.mongodb/mongodb-driver-sync "4.11.1"]
;; This wrapper library
[mongo-driver-3 "0.7.0"]
[mongo-driver-3 "0.8.0"]
```
## Getting started
@ -104,6 +104,10 @@ As an example:
;; Find a single document or return nil
(mc/find-one db "test" {:v "world"} {:keywordize? false})
; => {"v" "world"}
;; Avoid laziness in queries
(mc/find db "test" {} {:realise-fn (partial into [])}
; => [...]
```
While most options are supported directly, sometimes you may need to some extra control.
@ -181,6 +185,13 @@ use `with-open` so the session is closed after both successful and failed transa
(mc/insert-one my-db "coll" {:name "world"})))
```
## Development
1. Run mongo (e.g. via docker):
- `docker run -it --rm -p 27017:27017 mongo`
2. Run tests
- `lein test`
## License
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php

View file

@ -1,4 +1,4 @@
(defproject mongo-driver-3 "0.7.0"
(defproject mongo-driver-3 "0.9.0-SNAPSHOT"
:description "A Clojure wrapper for the Java MongoDB driver 3.11/4.0+."
:url "https://github.com/gnarroway/mongo-driver-3"
:license {:name "The MIT License"
@ -11,4 +11,4 @@
:plugins [[lein-cljfmt "0.6.4"]]
:profiles {:dev {:dependencies [[org.clojure/clojure "1.11.1"]
[org.mongodb/mongodb-driver-sync "4.7.1"]]}})
[org.mongodb/mongodb-driver-sync "4.11.1"]]}})

View file

@ -1,6 +1,7 @@
(ns mongo-driver-3.client
(:refer-clojure :exclude [find])
(:require [mongo-driver-3.model :as m])
(:require [mongo-driver-3.model :as m]
[mongo-driver-3.iterable :as iterable])
(:import (com.mongodb.client MongoClients MongoClient ClientSession MongoDatabase TransactionBody)
(com.mongodb ConnectionString ClientSessionOptions TransactionOptions)
(java.util.concurrent TimeUnit)))
@ -15,16 +16,15 @@
`connection-string` is a mongo connection string, e.g. mongodb://localhost:27107
If a connecting string is not passed in, it will connect to the default localhost instance."
([] (MongoClients/create))
([^String connection-string]
(MongoClients/create connection-string)))
(^MongoClient [] (MongoClients/create))
(^MongoClient [^String connection-string] (MongoClients/create connection-string)))
(defn get-db
"Gets a database by name
`client` is a MongoClient, e.g. resulting from calling `connect`
`name` is the name of the database to get."
[^MongoClient client ^String name]
^MongoDatabase [^MongoClient client ^String name]
(.getDatabase client name))
(defn close
@ -41,16 +41,20 @@
- `opts` (optional), a map of:
- `:name-only?` returns just the string names
- `:keywordize?` keywordize the keys of return results, default: true. Only applicable if `:name-only?` is false.
- `:raw?` return the mongo iterable directly instead of processing into a seq, default: false
- `:raw?` return the mongo iterable directly instead of processing into a clj data-structure, default: false
- `:realise-fn` how to realise the MongoIterable, default: `clojure.core/sequence` (i.e. lazily)
- `:session` a ClientSession"
([^MongoDatabase db] (list-collections db {}))
([^MongoDatabase db {:keys [raw? keywordize? ^ClientSession session] :or {keywordize? true}}]
([^MongoDatabase db {:keys [raw? keywordize? ^ClientSession session realise-fn]
:or {keywordize? true
realise-fn sequence}}]
(let [it (if session
(.listCollections db session)
(.listCollections db))]
(if-not raw?
(map #(m/from-document % keywordize?) (seq it))
it))))
(if raw?
it
(realise-fn ;; accomodate users who don't want to use lazy-seqs
(iterable/documents it keywordize?))))))
(defn list-collection-names
"Lists collection names in a database, returning as a seq of strings unless otherwise configured.
@ -66,9 +70,9 @@
(let [it (if-let [^ClientSession session (:session opts)]
(.listCollectionNames db session)
(.listCollectionNames db))]
(if-not (:raw? opts)
(seq it)
it))))
(if (:raw? opts)
it
(seq it)))))
(defn ->TransactionOptions
"Coerces options map into a TransactionOptions. See `start-session` for usage."

View file

@ -1,7 +1,8 @@
(ns mongo-driver-3.collection
(:refer-clojure :exclude [find empty? drop])
(:require [mongo-driver-3.model :refer :all]
[mongo-driver-3.client :refer [*session*]])
[mongo-driver-3.client :refer [*session*]]
[mongo-driver-3.iterable :as iterable])
(:import (com.mongodb MongoNamespace)
(com.mongodb.client MongoDatabase MongoCollection ClientSession)
(com.mongodb.client.model IndexModel)
@ -62,23 +63,27 @@
- `:batch-size` Documents to return per batch, e.g. 1
- `:bypass-document-validation?` Boolean
- `:keywordize?` keywordize the keys of return results, default: true
- `:realise-fn` how to realise the MongoIterable, default: `clojure.core/sequence` (i.e. lazily)
- `:raw?` return the mongo AggregateIterable directly instead of processing into a seq, default: false
- `:session` a ClientSession"
([^MongoDatabase db coll pipeline]
(aggregate db coll pipeline {}))
([^MongoDatabase db coll pipeline opts]
(let [{:keys [^ClientSession session allow-disk-use? ^Integer batch-size bypass-document-validation? keywordize? raw?] :or {keywordize? true raw? false}} opts
(let [{:keys [^ClientSession session allow-disk-use? ^Integer batch-size bypass-document-validation? keywordize? raw? realise-fn]
:or {keywordize? true
realise-fn sequence}} opts
^ClientSession session (or session *session*)
it (cond-> (if session
(.aggregate (collection db coll opts) session ^List (map document pipeline))
(.aggregate (collection db coll opts) ^List (map document pipeline)))
(some? allow-disk-use?) (.allowDiskUse allow-disk-use?)
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?)
batch-size (.batchSize batch-size))]
(some? allow-disk-use?) (.allowDiskUse allow-disk-use?)
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?)
batch-size (.batchSize batch-size))]
(if-not raw?
(map (fn [x] (from-document x keywordize?)) (seq it))
it))))
(if raw?
it
(realise-fn ;; accomodate users who don't want to use lazy-seqs
(iterable/documents it keywordize?))))))
(defn bulk-write
"Executes a mix of inserts, updates, replaces, and deletes.
@ -190,26 +195,30 @@
- `:sort` document representing sort order, e.g. {:timestamp -1}
- `:projection` document representing fields to return, e.g. {:_id 0}
- `:keywordize?` keywordize the keys of return results, default: true
- `:realise-fn` how to realise the MongoIterable, default: `clojure.core/sequence` (i.e. lazily)
- `:raw?` return the mongo FindIterable directly instead of processing into a seq, default: false
- `:session` a ClientSession
Additionally takes options specified in `collection`."
([^MongoDatabase db coll q]
(find db coll q {}))
([^MongoDatabase db coll q opts]
(let [{:keys [limit skip sort projection ^ClientSession session keywordize? raw?] :or {keywordize? true raw? false}} opts]
(let [^ClientSession session (or session *session*)
it (cond-> (if session
(.find (collection db coll opts) session (document q))
(.find (collection db coll opts) (document q)))
limit (.limit limit)
skip (.skip skip)
sort (.sort (document sort))
projection (.projection (document projection)))]
([^MongoDatabase db coll q {:keys [limit skip sort projection ^ClientSession session keywordize? raw? realise-fn]
:or {keywordize? true
realise-fn sequence}
:as opts}]
(let [^ClientSession session (or session *session*)
it (cond-> (if session
(.find (collection db coll opts) session (document q))
(.find (collection db coll opts) (document q)))
limit (.limit limit)
skip (.skip skip)
sort (.sort (document sort))
projection (.projection (document projection)))]
(if-not raw?
(map (fn [x] (from-document x keywordize?)) (seq it))
it)))))
(if raw?
it
(realise-fn ;; accomodate users who don't want to use lazy-seqs
(iterable/documents it keywordize?))))))
(defn find-one
"Finds a single document and returns it as a clojure map, or nil if not found.
@ -493,7 +502,7 @@
(create-indexes db coll indexes {}))
([^MongoDatabase db coll indexes opts]
(->> indexes
(map (fn [x] (IndexModel. (document (:keys x)) (->IndexOptions x))))
(mapv (fn [x] (IndexModel. (document (:keys x)) (->IndexOptions x))))
(.createIndexes (collection db coll opts)))))
(defn list-indexes
@ -501,5 +510,7 @@
([^MongoDatabase db coll]
(list-indexes db coll {}))
([^MongoDatabase db coll opts]
(->> (.listIndexes (collection db coll opts))
(map #(from-document % true)))))
(let [it (.listIndexes (collection db coll opts))
realise-fn (:realise-fn opts sequence)]
(realise-fn
(iterable/documents it true)))))

View file

@ -1,10 +1,36 @@
(ns mongo-driver-3.data-literals
(:import (org.bson.types ObjectId)
(java.io Writer)))
(java.io Writer)
(java.util Date)
(java.nio ByteBuffer)))
(defmethod print-method ObjectId [c ^Writer w] (.write w ^String (str "#mongo/id \"" (.toHexString c) "\"")))
(defmethod print-dup ObjectId [c ^Writer w] (.write w ^String (str "#mongo/id \"" (.toHexString c) "\"")))
(defmethod print-method ObjectId [^ObjectId c ^Writer w] (.write w (str "#mongo/id " \" (.toHexString c) \")))
(defmethod print-dup ObjectId [^ObjectId c ^Writer w] (.write w (str "#mongo/id " \" (.toHexString c) \")))
(defn mongo-id [o]
(ObjectId. o))
(defprotocol AsObjectId
(oid-from [this]))
(extend-protocol AsObjectId
(Class/forName "[B")
(oid-from [this] (ObjectId. ^bytes this))
nil
(oid-from [_] (ObjectId.))
String
(oid-from [this] (ObjectId. this))
Date
(oid-from [this] (ObjectId. this))
ByteBuffer
(oid-from [this] (ObjectId. this))
)
(defn mongo-id ;; https://mongodb.github.io/mongo-java-driver/4.8/apidocs/bson/org/bson/types/ObjectId.html
(^ObjectId [] (ObjectId.))
(^ObjectId [o] (oid-from o))
(^ObjectId [o1 o2]
(if (and (int? o1)
(int? o2))
(ObjectId. (int o1) (int o2))
(ObjectId. ^Date o1 (int o2)))))

View file

@ -0,0 +1,8 @@
(ns mongo-driver-3.iterable
(:require [mongo-driver-3.model :as m]))
(defn documents
"Given a MongoIterable <it>, returns an eduction which will
eventually yield all the documents (per `m/from-document`)."
[it keywordize?]
(eduction (map #(m/from-document % keywordize?)) it))

View file

@ -3,7 +3,7 @@
(org.bson Document)
(java.util.concurrent TimeUnit)
(com.mongodb WriteConcern ReadPreference ReadConcern)
(clojure.lang Ratio Keyword Named IPersistentMap)
(clojure.lang Ratio Named IPersistentMap)
(java.util Collection List Date)
(org.bson.types Decimal128)))
@ -16,8 +16,8 @@
(defn read-dates-as-instants! []
(extend-protocol ConvertToDocument
Date
(from-document [input _]
Date
(document [input _]
(.toInstant ^Date input))))
(extend-protocol ConvertToDocument
@ -29,24 +29,22 @@
(document [^Ratio input]
(double input))
Keyword
(document [^Keyword input]
(.getName input))
Named
(document [^Named input]
(.getName input))
IPersistentMap
(document [^IPersistentMap input]
(let [o (Document.)]
(doseq [[k v] input]
(.append o (document k) (document v)))
o))
(reduce-kv
(fn [^Document doc k v]
(doto doc
(.append (document k) (document v))))
(Document.)
input))
Collection
(document [^Collection input]
(map document input))
(mapv document input))
Object
(document [input]
@ -69,16 +67,18 @@
List
(from-document [^List input keywordize?]
(vec (map #(from-document % keywordize?) input)))
(mapv #(from-document % keywordize?) input))
Document
(from-document [^Document input keywordize?]
(reduce (if keywordize?
(fn [m ^String k]
(assoc m (keyword k) (from-document (.get input k) true)))
(fn [m ^String k]
(assoc m k (from-document (.get input k) false))))
{} (.keySet input))))
(persistent!
(reduce (if keywordize?
(fn [m ^String k]
(assoc! m (keyword k) (from-document (.get input k) true)))
(fn [m ^String k]
(assoc! m k (from-document (.get input k) false))))
(transient {})
(.keySet input)))))
;;; Config
@ -92,24 +92,25 @@
(defn ->ReadConcern
"Coerce `rc` into a ReadConcern if not nil. See `collection` for usage."
[{:keys [read-concern]}]
^ReadConcern [{:keys [read-concern]}]
(when read-concern
(if (instance? ReadConcern read-concern)
read-concern
(or (kw->ReadConcern read-concern) (throw (IllegalArgumentException.
(str "No match for read concern of " (name read-concern))))))))
(or (kw->ReadConcern read-concern)
(throw (IllegalArgumentException.
(str "No match for read concern of " (name read-concern))))))))
(defn ->ReadPreference
"Coerce `rp` into a ReadPreference if not nil. See `collection` for usage."
[{:keys [read-preference]}]
^ReadPreference [{:keys [read-preference]}]
(when read-preference
(if (instance? ReadPreference read-preference)
read-preference
(ReadPreference/valueOf (name read-preference)))))
(defn ^WriteConcern ->WriteConcern
(defn ->WriteConcern
"Coerces write-concern related options to a WriteConcern. See `collection` for usage."
[{:keys [write-concern ^Integer write-concern/w ^Long write-concern/w-timeout-ms ^Boolean write-concern/journal?]}]
^WriteConcern [{:keys [write-concern ^Integer write-concern/w ^Long write-concern/w-timeout-ms ^Boolean write-concern/journal?]}]
(when (some some? [write-concern w w-timeout-ms journal?])
(let [^WriteConcern wc (when write-concern
(if (instance? WriteConcern write-concern)
@ -120,17 +121,17 @@
w-timeout-ms (.withWTimeout w-timeout-ms (TimeUnit/MILLISECONDS))
(some? journal?) (.withJournal journal?)))))
(defn ^BulkWriteOptions ->BulkWriteOptions
(defn ->BulkWriteOptions
"Coerce options map into BulkWriteOptions. See `bulk-write` for usage."
[{:keys [bulk-write-options bypass-document-validation? ordered?]}]
^BulkWriteOptions [{:keys [bulk-write-options bypass-document-validation? ordered?]}]
(let [^BulkWriteOptions opts (or bulk-write-options (BulkWriteOptions.))]
(cond-> opts
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?)
(some? ordered?) (.ordered ordered?))))
(defn ^CountOptions ->CountOptions
(defn ->CountOptions
"Coerce options map into CountOptions. See `count-documents` for usage."
[{:keys [count-options hint limit max-time-ms skip]}]
^CountOptions [{:keys [count-options hint limit max-time-ms skip]}]
(let [^CountOptions opts (or count-options (CountOptions.))]
(cond-> opts
hint (.hint (document hint))
@ -138,15 +139,15 @@
max-time-ms (.maxTime max-time-ms (TimeUnit/MILLISECONDS))
skip (.skip skip))))
(defn ^DeleteOptions ->DeleteOptions
(defn ->DeleteOptions
"Coerce options map into DeleteOptions. See `delete-one` and `delete-many` for usage."
[{:keys [delete-options]}]
^DeleteOptions [{:keys [delete-options]}]
(let [^DeleteOptions opts (or delete-options (DeleteOptions.))]
opts))
(defn ^FindOneAndReplaceOptions ->FindOneAndReplaceOptions
(defn ->FindOneAndReplaceOptions
"Coerce options map into FindOneAndReplaceOptions. See `find-one-and-replace` for usage."
[{:keys [find-one-and-replace-options upsert? return-new? sort projection]}]
^FindOneAndReplaceOptions [{:keys [find-one-and-replace-options upsert? return-new? sort projection]}]
(let [^FindOneAndReplaceOptions opts (or find-one-and-replace-options (FindOneAndReplaceOptions.))]
(cond-> opts
(some? upsert?) (.upsert upsert?)
@ -154,9 +155,9 @@
sort (.sort (document sort))
projection (.projection (document projection)))))
(defn ^FindOneAndUpdateOptions ->FindOneAndUpdateOptions
(defn ->FindOneAndUpdateOptions
"Coerce options map into FindOneAndUpdateOptions. See `find-one-and-update` for usage."
[{:keys [find-one-and-update-options upsert? return-new? sort projection]}]
^FindOneAndUpdateOptions [{:keys [find-one-and-update-options upsert? return-new? sort projection]}]
(let [^FindOneAndUpdateOptions opts (or find-one-and-update-options (FindOneAndUpdateOptions.))]
(cond-> opts
(some? upsert?) (.upsert upsert?)
@ -175,40 +176,40 @@
(some? sparse?) (.sparse sparse?)
(some? unique?) (.unique unique?))))
(defn ^InsertManyOptions ->InsertManyOptions
(defn ->InsertManyOptions
"Coerce options map into InsertManyOptions. See `insert-many` for usage."
[{:keys [insert-many-options bypass-document-validation? ordered?]}]
^InsertManyOptions [{:keys [insert-many-options bypass-document-validation? ordered?]}]
(let [^InsertManyOptions opts (or insert-many-options (InsertManyOptions.))]
(cond-> opts
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?)
(some? ordered?) (.ordered ordered?))))
(defn ^InsertOneOptions ->InsertOneOptions
(defn ->InsertOneOptions
"Coerce options map into InsertOneOptions. See `insert-one` for usage."
[{:keys [insert-one-options bypass-document-validation?]}]
^InsertOneOptions [{:keys [insert-one-options bypass-document-validation?]}]
(let [^InsertOneOptions opts (or insert-one-options (InsertOneOptions.))]
(cond-> opts
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?))))
(defn ^ReplaceOptions ->ReplaceOptions
(defn ->ReplaceOptions
"Coerce options map into ReplaceOptions. See `replace-one` and `replace-many` for usage."
[{:keys [replace-options upsert? bypass-document-validation?]}]
^ReplaceOptions [{:keys [replace-options upsert? bypass-document-validation?]}]
(let [^ReplaceOptions opts (or replace-options (ReplaceOptions.))]
(cond-> opts
(some? upsert?) (.upsert upsert?)
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?))))
(defn ^UpdateOptions ->UpdateOptions
(defn ->UpdateOptions
"Coerce options map into UpdateOptions. See `update-one` and `update-many` for usage."
[{:keys [update-options upsert? bypass-document-validation?]}]
^UpdateOptions [{:keys [update-options upsert? bypass-document-validation?]}]
(let [^UpdateOptions opts (or update-options (UpdateOptions.))]
(cond-> opts
(some? upsert?) (.upsert upsert?)
(some? bypass-document-validation?) (.bypassDocumentValidation bypass-document-validation?))))
(defn ^CreateCollectionOptions ->CreateCollectionOptions
(defn ->CreateCollectionOptions
"Coerce options map into CreateCollectionOptions. See `create` usage."
[{:keys [create-collection-options capped? max-documents max-size-bytes]}]
^CreateCollectionOptions [{:keys [create-collection-options capped? max-documents max-size-bytes]}]
(let [^CreateCollectionOptions opts (or create-collection-options (CreateCollectionOptions.))]
(cond-> opts
(some? capped?) (.capped capped?)

View file

@ -144,7 +144,11 @@
(is (instance? FindIterable (mc/find db "test" {} {:raw? true}))))
(testing "keywordize"
(is (= [{"id" 1}] (mc/find db "test" {} {:keywordize? false :projection {:_id 0 :id 1} :limit 1}))))))
(is (= [{"id" 1}] (mc/find db "test" {} {:keywordize? false :projection {:_id 0 :id 1} :limit 1}))))
(testing "realise-fn"
(is (seq? (mc/find db "test" {})))
(is (vector? (mc/find db "test" {} {:realise-fn (partial into [])}))))))
(deftest ^:integration test-find-one
(let [db (new-db @client)
@ -349,12 +353,7 @@
(testing "not existing"
(let [db (new-db @client)
_ (mc/create db "my-coll")]
(is (true? (coll-exists? db "my-coll")))))
(testing "existing"
(let [db (new-db @client)
_ (mc/create db "my-coll")]
(is (thrown? Exception (mc/create db "my-coll"))))))
(is (true? (coll-exists? db "my-coll"))))))
(deftest ^:integration test-rename
(testing "not existing"
@ -387,7 +386,11 @@
(deftest ^:integration test-list-indexes
(let [db (new-db @client)
_ (mc/create db "test")]
(is (= 1 (count (mc/list-indexes db "test"))) "has default index")))
(is (= 1 (count (mc/list-indexes db "test"))) "has default index")
(testing "realise-fn"
(is (seq? (mc/list-indexes db "test")))
(is (vector? (mc/list-indexes db "test" {:realise-fn (partial into [])}))))))
(deftest ^:integration test-create-index
(let [db (new-db @client)

View file

@ -212,7 +212,7 @@
(testing "replace one"
(is (instance? ReplaceOneModel (m/write-model [:replace-one {:filter {:a "b"} :replacement {:a "c"}}])))
(are [expected arg]
(= expected (.isUpsert (.getOptions (m/write-model [:replace-one {:filter {:a "b"} :replacement {:a "c"} :upsert? arg}]))))
(= expected (.isUpsert (.getReplaceOptions (m/write-model [:replace-one {:filter {:a "b"} :replacement {:a "c"} :upsert? arg}]))))
true true
false false
false nil))
@ -220,7 +220,7 @@
(testing "update many"
(is (instance? UpdateManyModel (m/write-model [:update-many {:filter {:a "b"} :update {"$set" {:a "c"}}}])))
(are [expected arg]
(= expected (.isUpsert (.getOptions (m/write-model [:update-many {:filter {:a "b"} :update {"$set" {:a "c"}} :upsert? arg}]))))
(= expected (.isUpsert (.getOptions ^UpdateManyModel (m/write-model [:update-many {:filter {:a "b"} :update {"$set" {:a "c"}} :upsert? arg}]))))
true true
false false
false nil))