move model helpers to their own ns

This commit is contained in:
George Narroway 2020-01-09 22:54:54 +08:00
parent 4942c3426c
commit cb684136e5
5 changed files with 411 additions and 399 deletions

View file

@ -1,6 +1,6 @@
(ns mongo-driver-3.client
(:refer-clojure :exclude [find])
(:require [mongo-driver-3.collection :as mc])
(:require [mongo-driver-3.model :as m])
(:import (com.mongodb.client MongoClients MongoClient ClientSession MongoDatabase TransactionBody)
(com.mongodb ConnectionString ClientSessionOptions TransactionOptions)
(java.util.concurrent TimeUnit)))
@ -49,7 +49,7 @@
(.listCollections db session)
(.listCollections db))]
(if-not raw?
(map #(mc/from-document % keywordize?) (seq it))
(map #(m/from-document % keywordize?) (seq it))
it))))
(defn list-collection-names
@ -73,9 +73,9 @@
(defn ->TransactionOptions
"Coerces options map into a TransactionOptions. See `start-session` for usage."
[{:keys [max-commit-time-ms] :as opts}]
(let [rp (mc/->ReadPreference opts)
rc (mc/->ReadConcern opts)
wc (mc/->WriteConcern opts)]
(let [rp (m/->ReadPreference opts)
rc (m/->ReadConcern opts)
wc (m/->WriteConcern opts)]
(cond-> (TransactionOptions/builder)
max-commit-time-ms (.maxCommitTime max-commit-time-ms (TimeUnit/MILLISECONDS))

View file

@ -1,123 +1,16 @@
(ns mongo-driver-3.collection
(:refer-clojure :exclude [find empty? drop])
(:import (clojure.lang Ratio Keyword Named IPersistentMap)
(com.mongodb ReadConcern ReadPreference WriteConcern MongoNamespace)
(:require [mongo-driver-3.model :refer :all])
(:import (com.mongodb MongoNamespace)
(com.mongodb.client MongoDatabase MongoCollection ClientSession)
(com.mongodb.client.model InsertOneOptions InsertManyOptions DeleteOptions FindOneAndUpdateOptions ReturnDocument FindOneAndReplaceOptions CountOptions CreateCollectionOptions RenameCollectionOptions IndexOptions IndexModel UpdateOptions ReplaceOptions)
(java.util List Collection)
(java.util.concurrent TimeUnit)
(org.bson Document)
(org.bson.types Decimal128)))
(com.mongodb.client.model IndexModel)
(java.util List)
(org.bson Document)))
(set! *warn-on-reflection* true)
;;; Conversions
(defprotocol ConvertToDocument
(^Document document [input] "Convert from clojure to Mongo Document"))
(extend-protocol ConvertToDocument
nil
(document [_]
nil)
Ratio
(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))
Collection
(document [^Collection input]
(map document input))
Object
(document [input]
input))
(defprotocol ConvertFromDocument
(from-document [input keywordize?] "Converts Mongo Document to Clojure"))
(extend-protocol ConvertFromDocument
nil
(from-document [input _]
input)
Object
(from-document [input _] input)
Decimal128
(from-document [^Decimal128 input _]
(.bigDecimalValue input))
List
(from-document [^List input keywordize?]
(vec (map #(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))))
;;; Collection
(def kw->ReadConcern
{:available (ReadConcern/AVAILABLE)
:default (ReadConcern/DEFAULT)
:linearizable (ReadConcern/LINEARIZABLE)
:local (ReadConcern/LOCAL)
:majority (ReadConcern/MAJORITY)
:snapshot (ReadConcern/SNAPSHOT)})
(defn ->ReadConcern
"Coerce `rc` into a ReadConcern if not nil. See `collection` for usage."
[{: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))))))))
(defn ->ReadPreference
"Coerce `rp` into a ReadPreference if not nil. See `collection` for usage."
[{:keys [read-preference]}]
(when read-preference
(if (instance? ReadPreference read-preference)
read-preference
(ReadPreference/valueOf (name read-preference)))))
(defn ^WriteConcern ->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?]}]
(when (some some? [write-concern w w-timeout-ms journal?])
(let [^WriteConcern wc (when write-concern
(if (instance? WriteConcern write-concern)
write-concern
(WriteConcern/valueOf (name write-concern))))]
(cond-> (or wc (WriteConcern/ACKNOWLEDGED))
w (.withW w)
w-timeout-ms (.withWTimeout w-timeout-ms (TimeUnit/MILLISECONDS))
(some? journal?) (.withJournal journal?)))))
(defn ^MongoCollection collection
"Coerces `coll` to a MongoCollection with some options.
@ -148,9 +41,9 @@
rc (->ReadConcern opts)
wc (->WriteConcern opts)]
(cond-> ^MongoCollection coll'
rp (.withReadPreference rp)
rc (.withReadConcern rc)
wc (.withWriteConcern wc)))))
rp (.withReadPreference rp)
rc (.withReadConcern rc)
wc (.withWriteConcern wc)))))
;;; CRUD functions
@ -177,24 +70,14 @@
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))))
(defn ^CountOptions ->CountOptions
"Coerce options map into CountOptions. See `count-documents` for usage."
[{:keys [count-options hint limit max-time-ms skip]}]
(let [^CountOptions opts (or count-options (CountOptions.))]
(cond-> opts
hint (.hint (document hint))
limit (.limit limit)
max-time-ms (.maxTime max-time-ms (TimeUnit/MILLISECONDS))
skip (.skip skip))))
(defn count-documents
"Count documents in a collection, optionally matching a filter query `q`.
@ -223,12 +106,6 @@
(.countDocuments (collection db coll opts) session (document q) opts')
(.countDocuments (collection db coll opts) (document q) opts')))))
(defn ^DeleteOptions ->DeleteOptions
"Coerce options map into DeleteOptions. See `delete-one` and `delete-many` for usage."
[{:keys [delete-options]}]
(let [^DeleteOptions opts (or delete-options (DeleteOptions.))]
opts))
(defn delete-one
"Deletes a single document from a collection and returns a DeleteResult.
@ -294,10 +171,10 @@
(let [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)))]
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))
@ -312,16 +189,6 @@
([^MongoDatabase db coll q opts]
(first (find db coll q (assoc opts :limit 1 :raw? false)))))
(defn ^FindOneAndUpdateOptions ->FindOneAndUpdateOptions
"Coerce options map into FindOneAndUpdateOptions. See `find-one-and-update` for usage."
[{: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?)
return-new? (.returnDocument (ReturnDocument/AFTER))
sort (.sort (document sort))
projection (.projection (document projection)))))
(defn find-one-and-update
"Atomically find a document (at most one) and modify it.
@ -352,16 +219,6 @@
(.findOneAndUpdate (collection db coll opts) (document q) (document update) opts'))
(from-document keywordize?)))))
(defn ^FindOneAndReplaceOptions ->FindOneAndReplaceOptions
"Coerce options map into FindOneAndReplaceOptions. See `find-one-and-replace` for usage."
[{: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?)
return-new? (.returnDocument (ReturnDocument/AFTER))
sort (.sort (document sort))
projection (.projection (document projection)))))
(defn find-one-and-replace
"Atomically find a document (at most one) and replace it.
@ -392,14 +249,6 @@
(.findOneAndReplace (collection db coll opts) (document q) (document doc) opts'))
(from-document keywordize?)))))
(defn ^InsertOneOptions ->InsertOneOptions
"Coerce options map into InsertOneOptions. See `insert-one` for usage."
[{:keys [insert-one-options bypass-document-validation?]}]
(let [^InsertOneOptions opts (or insert-one-options (InsertOneOptions.))]
(when (some? bypass-document-validation?) (.bypassDocumentValidation opts bypass-document-validation?))
opts))
(defn insert-one
"Inserts a single document into a collection, and returns nil.
If the document does not have an _id field, it will be auto-generated by the underlying driver.
@ -424,14 +273,6 @@
(.insertOne (collection db coll opts) session (document doc) opts')
(.insertOne (collection db coll opts) (document doc) opts')))))
(defn ^InsertManyOptions ->InsertManyOptions
"Coerce options map into InsertManyOptions. See `insert-many` for usage."
[{: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 insert-many
"Inserts multiple documents into a collection.
If a document does not have an _id field, it will be auto-generated by the underlying driver.
@ -457,14 +298,6 @@
(.insertMany (collection db coll opts) session ^List (map document docs) opts')
(.insertMany (collection db coll opts) ^List (map document docs) opts')))))
(defn ^ReplaceOptions ->ReplaceOptions
"Coerce options map into ReplaceOptions. See `replace-one` and `replace-many` for usage."
[{: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 replace-one
"Replace a single document in a collection and returns an UpdateResult.
@ -489,14 +322,6 @@
(.replaceOne (collection db coll opts) session (document q) (document doc) (->ReplaceOptions opts))
(.replaceOne (collection db coll opts) (document q) (document doc) (->ReplaceOptions opts)))))
(defn ^UpdateOptions ->UpdateOptions
"Coerce options map into UpdateOptions. See `update-one` and `update-many` for usage."
[{: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 update-one
"Updates a single document in a collection and returns an UpdateResult.
@ -547,15 +372,6 @@
;;; Admin functions
(defn ^CreateCollectionOptions ->CreateCollectionOptions
"Coerce options map into CreateCollectionOptions. See `create` usage."
[{:keys [create-collection-options capped? max-documents max-size-bytes]}]
(let [^CreateCollectionOptions opts (or create-collection-options (CreateCollectionOptions.))]
(cond-> opts
(some? capped?) (.capped capped?)
max-documents (.maxDocuments max-documents)
max-size-bytes (.sizeInBytes max-size-bytes))))
(defn create
"Creates a collection
@ -575,13 +391,6 @@
(let [opts' (->CreateCollectionOptions opts)]
(.createCollection db coll opts'))))
(defn ^RenameCollectionOptions ->RenameCollectionOptions
"Coerce options map into RenameCollectionOptions. See `rename` usage."
[{:keys [rename-collection-options drop-target?]}]
(let [^RenameCollectionOptions opts (or rename-collection-options (RenameCollectionOptions.))]
(cond-> opts
(some? drop-target?) (.dropTarget drop-target?))))
(defn rename
"Renames `coll` to `new-coll` in the same DB.
@ -608,17 +417,6 @@
[^MongoDatabase db coll]
(.drop (collection db coll)))
(defn ^IndexOptions ->IndexOptions
"Coerces an options map into an IndexOptions.
See `create-index` for usage"
[{:keys [index-options name sparse? unique?]}]
(let [^IndexOptions opts (or index-options (IndexOptions.))]
(cond-> opts
name (.name name)
(some? sparse?) (.sparse sparse?)
(some? unique?) (.unique unique?))))
(defn create-index
"Creates an index

View file

@ -0,0 +1,211 @@
(ns mongo-driver-3.model
(:import (com.mongodb.client.model CountOptions DeleteOptions ReturnDocument FindOneAndUpdateOptions InsertOneOptions ReplaceOptions UpdateOptions CreateCollectionOptions RenameCollectionOptions InsertManyOptions FindOneAndReplaceOptions IndexOptions)
(org.bson Document)
(java.util.concurrent TimeUnit)
(com.mongodb WriteConcern ReadPreference ReadConcern)
(clojure.lang Ratio Keyword Named IPersistentMap)
(java.util Collection List)
(org.bson.types Decimal128)))
(set! *warn-on-reflection* true)
;;; Conversions
(defprotocol ConvertToDocument
(^Document document [input] "Convert from clojure to Mongo Document"))
(extend-protocol ConvertToDocument
nil
(document [_]
nil)
Ratio
(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))
Collection
(document [^Collection input]
(map document input))
Object
(document [input]
input))
(defprotocol ConvertFromDocument
(from-document [input keywordize?] "Converts Mongo Document to Clojure"))
(extend-protocol ConvertFromDocument
nil
(from-document [input _]
input)
Object
(from-document [input _] input)
Decimal128
(from-document [^Decimal128 input _]
(.bigDecimalValue input))
List
(from-document [^List input keywordize?]
(vec (map #(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))))
;;; Config
(def kw->ReadConcern
{:available (ReadConcern/AVAILABLE)
:default (ReadConcern/DEFAULT)
:linearizable (ReadConcern/LINEARIZABLE)
:local (ReadConcern/LOCAL)
:majority (ReadConcern/MAJORITY)
:snapshot (ReadConcern/SNAPSHOT)})
(defn ->ReadConcern
"Coerce `rc` into a ReadConcern if not nil. See `collection` for usage."
[{: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))))))))
(defn ->ReadPreference
"Coerce `rp` into a ReadPreference if not nil. See `collection` for usage."
[{:keys [read-preference]}]
(when read-preference
(if (instance? ReadPreference read-preference)
read-preference
(ReadPreference/valueOf (name read-preference)))))
(defn ^WriteConcern ->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?]}]
(when (some some? [write-concern w w-timeout-ms journal?])
(let [^WriteConcern wc (when write-concern
(if (instance? WriteConcern write-concern)
write-concern
(WriteConcern/valueOf (name write-concern))))]
(cond-> (or wc (WriteConcern/ACKNOWLEDGED))
w (.withW w)
w-timeout-ms (.withWTimeout w-timeout-ms (TimeUnit/MILLISECONDS))
(some? journal?) (.withJournal journal?)))))
(defn ^CountOptions ->CountOptions
"Coerce options map into CountOptions. See `count-documents` for usage."
[{:keys [count-options hint limit max-time-ms skip]}]
(let [^CountOptions opts (or count-options (CountOptions.))]
(cond-> opts
hint (.hint (document hint))
limit (.limit limit)
max-time-ms (.maxTime max-time-ms (TimeUnit/MILLISECONDS))
skip (.skip skip))))
(defn ^DeleteOptions ->DeleteOptions
"Coerce options map into DeleteOptions. See `delete-one` and `delete-many` for usage."
[{:keys [delete-options]}]
(let [^DeleteOptions opts (or delete-options (DeleteOptions.))]
opts))
(defn ^FindOneAndReplaceOptions ->FindOneAndReplaceOptions
"Coerce options map into FindOneAndReplaceOptions. See `find-one-and-replace` for usage."
[{: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?)
return-new? (.returnDocument (ReturnDocument/AFTER))
sort (.sort (document sort))
projection (.projection (document projection)))))
(defn ^FindOneAndUpdateOptions ->FindOneAndUpdateOptions
"Coerce options map into FindOneAndUpdateOptions. See `find-one-and-update` for usage."
[{: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?)
return-new? (.returnDocument (ReturnDocument/AFTER))
sort (.sort (document sort))
projection (.projection (document projection)))))
(defn ^IndexOptions ->IndexOptions
"Coerces an options map into an IndexOptions.
See `create-index` for usage"
[{:keys [index-options name sparse? unique?]}]
(let [^IndexOptions opts (or index-options (IndexOptions.))]
(cond-> opts
name (.name name)
(some? sparse?) (.sparse sparse?)
(some? unique?) (.unique unique?))))
(defn ^InsertManyOptions ->InsertManyOptions
"Coerce options map into InsertManyOptions. See `insert-many` for usage."
[{: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
"Coerce options map into InsertOneOptions. See `insert-one` for usage."
[{: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
"Coerce options map into ReplaceOptions. See `replace-one` and `replace-many` for usage."
[{: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
"Coerce options map into UpdateOptions. See `update-one` and `update-many` for usage."
[{: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
"Coerce options map into CreateCollectionOptions. See `create` usage."
[{:keys [create-collection-options capped? max-documents max-size-bytes]}]
(let [^CreateCollectionOptions opts (or create-collection-options (CreateCollectionOptions.))]
(cond-> opts
(some? capped?) (.capped capped?)
max-documents (.maxDocuments max-documents)
max-size-bytes (.sizeInBytes max-size-bytes))))
(defn ^RenameCollectionOptions ->RenameCollectionOptions
"Coerce options map into RenameCollectionOptions. See `rename` usage."
[{:keys [rename-collection-options drop-target?]}]
(let [^RenameCollectionOptions opts (or rename-collection-options (RenameCollectionOptions.))]
(cond-> opts
(some? drop-target?) (.dropTarget drop-target?))))

View file

@ -2,186 +2,10 @@
(:require [clojure.test :refer :all]
[mongo-driver-3.client :as mg]
[mongo-driver-3.collection :as mc])
(:import (com.mongodb ReadConcern ReadPreference WriteConcern)
(java.util.concurrent TimeUnit)
(com.mongodb.client.model InsertOneOptions InsertManyOptions DeleteOptions FindOneAndUpdateOptions ReturnDocument FindOneAndReplaceOptions CountOptions UpdateOptions ReplaceOptions IndexOptions CreateCollectionOptions RenameCollectionOptions)
(java.time ZoneId LocalDate LocalTime LocalDateTime)
(:import (java.time ZoneId LocalDate LocalTime LocalDateTime)
(java.util Date UUID)
(com.mongodb.client FindIterable)))
;;; Unit
(deftest test->ReadConcern
(is (nil? (mc/->ReadConcern {})))
(is (thrown? IllegalArgumentException (mc/->ReadConcern {:read-concern "invalid"})))
(is (instance? ReadConcern (mc/->ReadConcern {:read-concern :available}))))
(deftest test->ReadPreference
(is (nil? (mc/->ReadPreference {})))
(is (thrown? IllegalArgumentException (mc/->ReadPreference {:read-preference "invalid"})))
(is (instance? ReadPreference (mc/->ReadPreference {:read-preference :primary}))))
(deftest test->WriteConcern
(is (= (WriteConcern/W1) (mc/->WriteConcern {:write-concern :w1})) "accepts kw")
(is (= (WriteConcern/W1) (mc/->WriteConcern {:write-concern (WriteConcern/W1)})) "accepts WriteConcern")
(is (= (WriteConcern/ACKNOWLEDGED) (mc/->WriteConcern {:write-concern "invalid"})) "defaults to acknowledged")
(is (= 1 (.getW (mc/->WriteConcern {:write-concern/w 1}))) "set w")
(is (= 2 (.getW (mc/->WriteConcern {:write-concern (WriteConcern/W2)}))))
(is (= 1 (.getW (mc/->WriteConcern {:write-concern (WriteConcern/W2) :write-concern/w 1}))) "prefer granular option")
(is (true? (.getJournal (mc/->WriteConcern {:write-concern/journal? true}))) "can set journal")
(is (= 77 (.getWTimeout (mc/->WriteConcern {:write-concern/w-timeout-ms 77}) (TimeUnit/MILLISECONDS))) "can set timeout"))
(deftest test->InsertOneOptions
(is (instance? InsertOneOptions (mc/->InsertOneOptions {})))
(is (true? (.getBypassDocumentValidation (mc/->InsertOneOptions {:bypass-document-validation? true}))))
(is (true? (.getBypassDocumentValidation (mc/->InsertOneOptions
{:insert-one-options (.bypassDocumentValidation (InsertOneOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (mc/->InsertOneOptions
{:insert-one-options (.bypassDocumentValidation (InsertOneOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->ReplaceOptions
(is (instance? ReplaceOptions (mc/->ReplaceOptions {})))
(are [expected arg]
(= expected (.isUpsert (mc/->ReplaceOptions {:upsert? arg})))
true true
false false
false nil) (is (true? (.getBypassDocumentValidation (mc/->ReplaceOptions {:bypass-document-validation? true}))))
(is (true? (.getBypassDocumentValidation (mc/->ReplaceOptions
{:replace-options (.bypassDocumentValidation (ReplaceOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (mc/->ReplaceOptions
{:replace-options (.bypassDocumentValidation (ReplaceOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->UpdateOptions
(is (instance? UpdateOptions (mc/->UpdateOptions {})))
(are [expected arg]
(= expected (.isUpsert (mc/->UpdateOptions {:upsert? arg})))
true true
false false
false nil)
(is (true? (.getBypassDocumentValidation (mc/->UpdateOptions {:bypass-document-validation? true}))))
(is (true? (.getBypassDocumentValidation (mc/->UpdateOptions
{:update-options (.bypassDocumentValidation (UpdateOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (mc/->UpdateOptions
{:update-options (.bypassDocumentValidation (UpdateOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->InsertManyOptions
(is (instance? InsertManyOptions (mc/->InsertManyOptions {})))
(are [expected arg]
(= expected (.getBypassDocumentValidation (mc/->InsertManyOptions {:bypass-document-validation? arg})))
true true
false false
nil nil)
(are [expected arg]
(= expected (.isOrdered (mc/->InsertManyOptions {:ordered? arg})))
true true
false false
true nil)
(is (true? (.getBypassDocumentValidation (mc/->InsertManyOptions
{:insert-many-options (.bypassDocumentValidation (InsertManyOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (mc/->InsertManyOptions
{:insert-one-options (.bypassDocumentValidation (InsertManyOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->DeleteOptions
(is (instance? DeleteOptions (mc/->DeleteOptions {})))
(let [opts (DeleteOptions.)]
(is (= opts (mc/->DeleteOptions {:delete-options opts})) "configure directly")))
(deftest test->RenameCollectionOptions
(is (instance? RenameCollectionOptions (mc/->RenameCollectionOptions {})))
(are [expected arg]
(= expected (.isDropTarget (mc/->RenameCollectionOptions {:drop-target? arg})))
true true
false false
false nil)
(let [opts (RenameCollectionOptions.)]
(is (= opts (mc/->RenameCollectionOptions {:rename-collection-options opts})) "configure directly")))
(deftest test->FindOneAndUpdateOptions
(is (instance? FindOneAndUpdateOptions (mc/->FindOneAndUpdateOptions {})))
(let [opts (FindOneAndUpdateOptions.)]
(is (= opts (mc/->FindOneAndUpdateOptions {:find-one-and-update-options opts})) "configure directly"))
(are [expected arg]
(= expected (.isUpsert (mc/->FindOneAndUpdateOptions {:upsert? arg})))
true true
false false
false nil)
(are [expected arg]
(= expected (.getReturnDocument (mc/->FindOneAndUpdateOptions {:return-new? arg})))
(ReturnDocument/AFTER) true
(ReturnDocument/BEFORE) false
(ReturnDocument/BEFORE) nil)
(is (= {"_id" 1} (.getSort (mc/->FindOneAndUpdateOptions {:sort {:_id 1}}))))
(is (= {"_id" 1} (.getProjection (mc/->FindOneAndUpdateOptions {:projection {:_id 1}})))))
(deftest test->FindOneAndReplaceOptions
(is (instance? FindOneAndReplaceOptions (mc/->FindOneAndReplaceOptions {})))
(let [opts (FindOneAndReplaceOptions.)]
(is (= opts (mc/->FindOneAndReplaceOptions {:find-one-and-replace-options opts})) "configure directly"))
(are [expected arg]
(= expected (.isUpsert (mc/->FindOneAndReplaceOptions {:upsert? arg})))
true true
false false
false nil)
(are [expected arg]
(= expected (.getReturnDocument (mc/->FindOneAndReplaceOptions {:return-new? arg})))
(ReturnDocument/AFTER) true
(ReturnDocument/BEFORE) false
(ReturnDocument/BEFORE) nil)
(is (= {"_id" 1} (.getSort (mc/->FindOneAndReplaceOptions {:sort {:_id 1}}))))
(is (= {"_id" 1} (.getProjection (mc/->FindOneAndReplaceOptions {:projection {:_id 1}})))))
(deftest test->CountOptions
(is (instance? CountOptions (mc/->CountOptions {})))
(let [opts (CountOptions.)]
(is (= opts (mc/->CountOptions {:count-options opts})) "configure directly"))
(is (= {"a" 1} (.getHint (mc/->CountOptions {:hint {:a 1}}))))
(is (= 7 (.getLimit (mc/->CountOptions {:limit 7}))))
(is (= 2 (.getSkip (mc/->CountOptions {:skip 2}))))
(is (= 42 (.getMaxTime (mc/->CountOptions {:max-time-ms 42}) (TimeUnit/MILLISECONDS)))))
(deftest test->IndexOptions
(is (instance? IndexOptions (mc/->IndexOptions {})))
(are [expected arg]
(= expected (.isSparse (mc/->IndexOptions {:sparse? arg})))
true true
false false
false nil)
(are [expected arg]
(= expected (.isUnique (mc/->IndexOptions {:unique? arg})))
true true
false false
false nil)
(let [opts (IndexOptions.)]
(is (= opts (mc/->IndexOptions {:index-options opts})) "configure directly")))
(deftest test->CreateCollectionOptions
(are [expected arg]
(= expected (.isCapped (mc/->CreateCollectionOptions {:capped? arg})))
true true
false false
false nil)
(is (= 7 (.getMaxDocuments (mc/->CreateCollectionOptions {:max-documents 7}))))
(is (= 42 (.getSizeInBytes (mc/->CreateCollectionOptions {:max-size-bytes 42}))))
(let [opts (-> (CreateCollectionOptions.) (.maxDocuments 5))]
(is (= opts (mc/->CreateCollectionOptions {:create-collection-options opts})) "configure directly")
(is (= 5 (.getMaxDocuments (mc/->CreateCollectionOptions {:create-collection-options opts}))))
(is (= 7 (.getMaxDocuments (mc/->CreateCollectionOptions {:create-collection-options opts :max-documents 7})))
"can override")))
;;; Integration
; docker run -it --rm -p 27017:27017 mongo:4.2

View file

@ -0,0 +1,179 @@
(ns mongo-driver-3.model-test
(:require [clojure.test :refer :all]
[mongo-driver-3.model :as m])
(:import (com.mongodb ReadConcern ReadPreference WriteConcern)
(java.util.concurrent TimeUnit)
(com.mongodb.client.model InsertOneOptions InsertManyOptions DeleteOptions FindOneAndUpdateOptions ReturnDocument FindOneAndReplaceOptions CountOptions UpdateOptions ReplaceOptions IndexOptions CreateCollectionOptions RenameCollectionOptions)))
;;; Unit
(deftest test->ReadConcern
(is (nil? (m/->ReadConcern {})))
(is (thrown? IllegalArgumentException (m/->ReadConcern {:read-concern "invalid"})))
(is (instance? ReadConcern (m/->ReadConcern {:read-concern :available}))))
(deftest test->ReadPreference
(is (nil? (m/->ReadPreference {})))
(is (thrown? IllegalArgumentException (m/->ReadPreference {:read-preference "invalid"})))
(is (instance? ReadPreference (m/->ReadPreference {:read-preference :primary}))))
(deftest test->WriteConcern
(is (= (WriteConcern/W1) (m/->WriteConcern {:write-concern :w1})) "accepts kw")
(is (= (WriteConcern/W1) (m/->WriteConcern {:write-concern (WriteConcern/W1)})) "accepts WriteConcern")
(is (= (WriteConcern/ACKNOWLEDGED) (m/->WriteConcern {:write-concern "invalid"})) "defaults to acknowledged")
(is (= 1 (.getW (m/->WriteConcern {:write-concern/w 1}))) "set w")
(is (= 2 (.getW (m/->WriteConcern {:write-concern (WriteConcern/W2)}))))
(is (= 1 (.getW (m/->WriteConcern {:write-concern (WriteConcern/W2) :write-concern/w 1}))) "prefer granular option")
(is (true? (.getJournal (m/->WriteConcern {:write-concern/journal? true}))) "can set journal")
(is (= 77 (.getWTimeout (m/->WriteConcern {:write-concern/w-timeout-ms 77}) (TimeUnit/MILLISECONDS))) "can set timeout"))
(deftest test->InsertOneOptions
(is (instance? InsertOneOptions (m/->InsertOneOptions {})))
(is (true? (.getBypassDocumentValidation (m/->InsertOneOptions {:bypass-document-validation? true}))))
(is (true? (.getBypassDocumentValidation (m/->InsertOneOptions
{:insert-one-options (.bypassDocumentValidation (InsertOneOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (m/->InsertOneOptions
{:insert-one-options (.bypassDocumentValidation (InsertOneOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->ReplaceOptions
(is (instance? ReplaceOptions (m/->ReplaceOptions {})))
(are [expected arg]
(= expected (.isUpsert (m/->ReplaceOptions {:upsert? arg})))
true true
false false
false nil) (is (true? (.getBypassDocumentValidation (m/->ReplaceOptions {:bypass-document-validation? true}))))
(is (true? (.getBypassDocumentValidation (m/->ReplaceOptions
{:replace-options (.bypassDocumentValidation (ReplaceOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (m/->ReplaceOptions
{:replace-options (.bypassDocumentValidation (ReplaceOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->UpdateOptions
(is (instance? UpdateOptions (m/->UpdateOptions {})))
(are [expected arg]
(= expected (.isUpsert (m/->UpdateOptions {:upsert? arg})))
true true
false false
false nil)
(is (true? (.getBypassDocumentValidation (m/->UpdateOptions {:bypass-document-validation? true}))))
(is (true? (.getBypassDocumentValidation (m/->UpdateOptions
{:update-options (.bypassDocumentValidation (UpdateOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (m/->UpdateOptions
{:update-options (.bypassDocumentValidation (UpdateOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->InsertManyOptions
(is (instance? InsertManyOptions (m/->InsertManyOptions {})))
(are [expected arg]
(= expected (.getBypassDocumentValidation (m/->InsertManyOptions {:bypass-document-validation? arg})))
true true
false false
nil nil)
(are [expected arg]
(= expected (.isOrdered (m/->InsertManyOptions {:ordered? arg})))
true true
false false
true nil)
(is (true? (.getBypassDocumentValidation (m/->InsertManyOptions
{:insert-many-options (.bypassDocumentValidation (InsertManyOptions.) true)})))
"configure directly")
(is (false? (.getBypassDocumentValidation (m/->InsertManyOptions
{:insert-one-options (.bypassDocumentValidation (InsertManyOptions.) true)
:bypass-document-validation? false})))
"can override"))
(deftest test->DeleteOptions
(is (instance? DeleteOptions (m/->DeleteOptions {})))
(let [opts (DeleteOptions.)]
(is (= opts (m/->DeleteOptions {:delete-options opts})) "configure directly")))
(deftest test->RenameCollectionOptions
(is (instance? RenameCollectionOptions (m/->RenameCollectionOptions {})))
(are [expected arg]
(= expected (.isDropTarget (m/->RenameCollectionOptions {:drop-target? arg})))
true true
false false
false nil)
(let [opts (RenameCollectionOptions.)]
(is (= opts (m/->RenameCollectionOptions {:rename-collection-options opts})) "configure directly")))
(deftest test->FindOneAndUpdateOptions
(is (instance? FindOneAndUpdateOptions (m/->FindOneAndUpdateOptions {})))
(let [opts (FindOneAndUpdateOptions.)]
(is (= opts (m/->FindOneAndUpdateOptions {:find-one-and-update-options opts})) "configure directly"))
(are [expected arg]
(= expected (.isUpsert (m/->FindOneAndUpdateOptions {:upsert? arg})))
true true
false false
false nil)
(are [expected arg]
(= expected (.getReturnDocument (m/->FindOneAndUpdateOptions {:return-new? arg})))
(ReturnDocument/AFTER) true
(ReturnDocument/BEFORE) false
(ReturnDocument/BEFORE) nil)
(is (= {"_id" 1} (.getSort (m/->FindOneAndUpdateOptions {:sort {:_id 1}}))))
(is (= {"_id" 1} (.getProjection (m/->FindOneAndUpdateOptions {:projection {:_id 1}})))))
(deftest test->FindOneAndReplaceOptions
(is (instance? FindOneAndReplaceOptions (m/->FindOneAndReplaceOptions {})))
(let [opts (FindOneAndReplaceOptions.)]
(is (= opts (m/->FindOneAndReplaceOptions {:find-one-and-replace-options opts})) "configure directly"))
(are [expected arg]
(= expected (.isUpsert (m/->FindOneAndReplaceOptions {:upsert? arg})))
true true
false false
false nil)
(are [expected arg]
(= expected (.getReturnDocument (m/->FindOneAndReplaceOptions {:return-new? arg})))
(ReturnDocument/AFTER) true
(ReturnDocument/BEFORE) false
(ReturnDocument/BEFORE) nil)
(is (= {"_id" 1} (.getSort (m/->FindOneAndReplaceOptions {:sort {:_id 1}}))))
(is (= {"_id" 1} (.getProjection (m/->FindOneAndReplaceOptions {:projection {:_id 1}})))))
(deftest test->CountOptions
(is (instance? CountOptions (m/->CountOptions {})))
(let [opts (CountOptions.)]
(is (= opts (m/->CountOptions {:count-options opts})) "configure directly"))
(is (= {"a" 1} (.getHint (m/->CountOptions {:hint {:a 1}}))))
(is (= 7 (.getLimit (m/->CountOptions {:limit 7}))))
(is (= 2 (.getSkip (m/->CountOptions {:skip 2}))))
(is (= 42 (.getMaxTime (m/->CountOptions {:max-time-ms 42}) (TimeUnit/MILLISECONDS)))))
(deftest test->IndexOptions
(is (instance? IndexOptions (m/->IndexOptions {})))
(are [expected arg]
(= expected (.isSparse (m/->IndexOptions {:sparse? arg})))
true true
false false
false nil)
(are [expected arg]
(= expected (.isUnique (m/->IndexOptions {:unique? arg})))
true true
false false
false nil)
(let [opts (IndexOptions.)]
(is (= opts (m/->IndexOptions {:index-options opts})) "configure directly")))
(deftest test->CreateCollectionOptions
(are [expected arg]
(= expected (.isCapped (m/->CreateCollectionOptions {:capped? arg})))
true true
false false
false nil)
(is (= 7 (.getMaxDocuments (m/->CreateCollectionOptions {:max-documents 7}))))
(is (= 42 (.getSizeInBytes (m/->CreateCollectionOptions {:max-size-bytes 42}))))
(let [opts (-> (CreateCollectionOptions.) (.maxDocuments 5))]
(is (= opts (m/->CreateCollectionOptions {:create-collection-options opts})) "configure directly")
(is (= 5 (.getMaxDocuments (m/->CreateCollectionOptions {:create-collection-options opts}))))
(is (= 7 (.getMaxDocuments (m/->CreateCollectionOptions {:create-collection-options opts :max-documents 7})))
"can override")))