Merge pull request #10 from jimpil/master

various optimisations/fixes
This commit is contained in:
gnarroway 2024-02-07 10:44:13 +08:00 committed by GitHub
commit 9c2c899876
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 139 additions and 87 deletions

2
.gitignore vendored
View file

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

View file

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

View file

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

View file

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