From ccd3d7ab668a4bb2dc13efdb678263dcd5e14a2c Mon Sep 17 00:00:00 2001 From: Baishampayan Ghose Date: Sat, 12 May 2012 09:02:19 +0530 Subject: [PATCH] Add monger.collection/find-and-modify and associated tests. --- src/monger/collection.clj | 36 +++++++++++++++++ test/monger/test/atomic_modifiers_test.clj | 47 ++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/monger/collection.clj b/src/monger/collection.clj index 586fe59..74c578f 100644 --- a/src/monger/collection.clj +++ b/src/monger/collection.clj @@ -172,6 +172,42 @@ (from-db-object ^DBObject (find-one collection ref fields) keywordize))) +;; +;; monger.collection/find-and-modify +;; + +(defn ^DBObject find-and-modify + "Atomically modify a document (at most one) and return it. + + EXAMPLES: + + ;; Find and modify a document + (mgcol/find-and-modify collection { :language \"Python\" } { :language \"Clojure\" }) + + ;; If multiple documents match, choose the first one in the specified order + (mgcol/find-and-modify collection { :language \"Python\" } { :language \"Clojure\" } :sort { :language -1 }) + + ;; Remove the object before returning + (mgcol/find-and-modify collection { :language \"Python\" } {} :remove true) + + ;; Return the modified object instead of the old one + (mgcol/find-and-modify collection { :language \"Python\" } { :language \"Clojure\" } :return-new true) + + ;; Retrieve a subset of fields + (mgcol/find-and-modify collection { :language \"Python\" } { :language \"Clojure\" } :fields [ :language ]) + + ;; Create the object if it doesn't exist + (mgcol/find-and-modify collection { :language \"Factor\" } { :language \"Clojure\" } :upsert true) + + " + ([^String collection ^Map conditions ^Map document & { :keys [fields sort remove return-new upsert keywordize] :or + { fields nil sort nil remove false return-new false upsert false keywordize true }}] + (let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection) + maybe-fields (when fields (to-db-object (as-field-selector fields))) + maybe-sort (when sort (to-db-object sort))] + (from-db-object + ^DBObject (.findAndModify ^DBCollection coll ^DBObject (to-db-object conditions) maybe-fields maybe-sort remove + ^DBObject (to-db-object document) return-new upsert) keywordize)))) ;; ;; monger.collection/find-by-id diff --git a/test/monger/test/atomic_modifiers_test.clj b/test/monger/test/atomic_modifiers_test.clj index 3924b09..16014ba 100644 --- a/test/monger/test/atomic_modifiers_test.clj +++ b/test/monger/test/atomic_modifiers_test.clj @@ -291,3 +291,50 @@ (mgcol/insert coll { :_id oid :title title :measurements v }) (mgcol/update coll { :_id oid } { $rename { :measurements "results" } }) (is (= { :_id oid :title title :results v } (mgcol/find-map-by-id coll oid))))) + + +;; +;; find-and-modify +;; + +(deftest find-and-modify-a-single-document + (let [coll "docs" + oid (ObjectId.) + doc {:_id oid :name "Sophie Bangs" :level 42} + conditions {:name "Sophie Bangs"} + update {$inc {:level 1}}] + (mgcol/insert coll doc) + (let [res (mgcol/find-and-modify coll conditions update :return-new true)] + (is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 43}))))) + + +(deftest find-and-modify-remove-a-document + (let [coll "docs" + oid (ObjectId.) + doc {:_id oid :name "Sophie Bangs" :level 42} + conditions {:name "Sophie Bangs"}] + (mgcol/insert coll doc) + (let [res (mgcol/find-and-modify coll conditions {} :remove true)] + (is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42})) + (is (empty? (mgcol/find-maps coll conditions)))))) + + +(deftest find-and-modify-upsert-a-document + (let [coll "docs" + oid (ObjectId.) + doc {:_id oid :name "Sophie Bangs" :level 42}] + (let [res (mgcol/find-and-modify coll doc doc :upsert true)] + (is (empty? res)) + (is (select-keys (mgcol/find-map-by-id coll oid) [:name :level]) (dissoc doc :_id))))) + + +(deftest find-and-modify-after-sort + (let [coll "docs" + oid (ObjectId.) + oid2 (ObjectId.) + doc {:name "Sophie Bangs"} + doc1 (assoc doc :_id oid :level 42) + doc2 (assoc doc :_id oid2 :level 0)] + (mgcol/insert-batch coll [doc1 doc2]) + (let [res (mgcol/find-and-modify coll doc {$inc {:level 1}} :sort {:level -1})] + (is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42})))))