From 0d635721a1d2957eaa046666fd7dbd1b924281f3 Mon Sep 17 00:00:00 2001 From: Erik Bakstad Date: Thu, 13 Jun 2013 07:31:43 +0200 Subject: [PATCH 1/5] Added missing fns to multi/collection. Related to #53. --- src/clojure/monger/multi/collection.clj | 234 +++++++++++++++++++++- test/monger/test/multi/find_test.clj | 145 ++++++++++++++ test/monger/test/multi/inserting_test.clj | 101 ++++++++++ 3 files changed, 474 insertions(+), 6 deletions(-) create mode 100644 test/monger/test/multi/find_test.clj diff --git a/src/clojure/monger/multi/collection.clj b/src/clojure/monger/multi/collection.clj index 02c0d9f..910f2f0 100644 --- a/src/clojure/monger/multi/collection.clj +++ b/src/clojure/monger/multi/collection.clj @@ -4,7 +4,7 @@ Use these functions when you need to work with multiple databases or manage database and connection lifecycle explicitly." - (:refer-clojure :exclude [find remove count]) + (:refer-clojure :exclude [find remove count empty? distinct drop]) (:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor MapReduceCommand MapReduceCommand$OutputType] [java.util List Map] [clojure.lang IPersistentMap ISeq] @@ -60,11 +60,13 @@ ;; -;; monger.collection/find +;; monger.multi.collection/find ;; (defn ^DBCursor find "Like monger.collection/find but always takes a database as explicit argument" + ([^DB db ^String collection] + (.find (.getCollection db (name collection)))) ([^DB db ^String collection ^Map ref] (.find (.getCollection db (name collection)) (to-db-object ref))) @@ -75,6 +77,9 @@ (defn find-maps "Like monger.collection/find-maps but always takes a database as explicit argument" + ([^DB db ^String collection] + (with-open [dbc (find db collection)] + (map (fn [x] (from-db-object x true)) dbc))) ([^DB db ^String collection ^Map ref] (with-open [dbc (find db collection ref)] (map (fn [x] (from-db-object x true)) dbc))) @@ -82,8 +87,20 @@ (with-open [dbc (find db collection ref fields)] (map (fn [x] (from-db-object x true)) dbc)))) +(defn find-seq + "Like monger.collection/find-seq but always takes a database as explicit argument" + ([^DB db ^String collection] + (with-open [dbc (find db collection)] + (seq dbc))) + ([^DB db ^String collection ^Map ref] + (with-open [dbc (find db collection ref)] + (seq dbc))) + ([^DB db ^String collection ^Map ref fields] + (with-open [dbc (find db collection ref fields)] + (seq dbc)))) + ;; -;; monger.collection/find-one +;; monger.multi.collection/find-one ;; (defn ^DBObject find-one @@ -106,7 +123,22 @@ (from-db-object ^DBObject (find-one db collection ref fields) keywordize))) ;; -;; monger.collection/find-by-id +;; monger.multi.collection/find-and-modify +;; + +(defn ^DBObject find-and-modify + "Like monger.collection/find-and-modify but always takes a database as explicit argument" + ([^DB db ^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 [coll (.getCollection db (name collection)) + maybe-fields (when fields (as-field-selector fields)) + maybe-sort (when sort (to-db-object sort))] + (from-db-object + ^DBObject (.findAndModify ^DBCollection coll (to-db-object conditions) maybe-fields maybe-sort remove + (to-db-object document) return-new upsert) keywordize)))) + +;; +;; monger.multi.collection/find-by-id ;; (defn ^DBObject find-by-id @@ -125,10 +157,13 @@ (from-db-object ^DBObject (find-one-as-map db collection {:_id id}) true)) ([^DB db ^String collection id fields] (check-not-nil! id "id must not be nil") - (from-db-object ^DBObject (find-one-as-map db collection {:_id id} fields) true))) + (from-db-object ^DBObject (find-one-as-map db collection {:_id id} fields) true)) + ([^DB db ^String collection id fields keywordize] + (check-not-nil! id "id must not be nil") + (from-db-object ^DBObject (find-one-as-map db collection {:_id id} fields) keywordize))) ;; -;; monger.collection/count +;; monger.multi.collection/count ;; (defn count @@ -137,3 +172,190 @@ (.count (.getCollection db (name collection)) (to-db-object {}))) (^long [^DB db ^String collection ^Map conditions] (.count (.getCollection db (name collection)) (to-db-object conditions)))) + +(defn any? + "Like monger.collection/any? but always takes a database as explicit argument" + ([^DB db ^String collection] + (> (count db collection) 0)) + ([^DB db ^String collection ^Map conditions] + (> (count db collection conditions) 0))) + +(defn empty? + "Like monger.collection/empty? but always takes a database as explicit argument" + ([^DB db ^String collection] + (= (count db collection {}) 0))) + +(defn ^WriteResult update + "Like monger.collection/update but always takes a database as explicit argument" + ([^DB db ^String collection ^Map conditions ^Map document & {:keys [upsert multi write-concern] :or {upsert false + multi false + write-concern monger.core/*mongodb-write-concern*}}] + (.update (.getCollection db (name collection)) + (to-db-object conditions) + (to-db-object document) + upsert + multi + write-concern))) + +(defn ^WriteResult upsert + "Like monger.collection/upsert but always takes a database as explicit argument" + [^DB db ^String collection ^Map conditions ^Map document & {:keys [multi write-concern] :or {multi false + write-concern monger.core/*mongodb-write-concern*}}] + (update db collection conditions document :multi multi :write-concern write-concern :upsert true)) + +(defn ^WriteResult update-by-id + "Like monger.collection/update-by-id but always takes a database as explicit argument" + [^DB db ^String collection id ^Map document & {:keys [upsert write-concern] :or {upsert false + write-concern monger.core/*mongodb-write-concern*}}] + (check-not-nil! id "id must not be nil") + (.update (.getCollection db (name collection)) + (to-db-object {:_id id}) + (to-db-object document) + upsert + false + write-concern)) + +(defn ^WriteResult save + "Like monger.collection/save but always takes a database as explicit argument" + ([^DB db ^String collection ^Map document] + (.save (.getCollection db (name collection)) + (to-db-object document) + monger.core/*mongodb-write-concern*)) + ([^DB db ^String collection ^Map document ^WriteConcern write-concern] + (.save (.getCollection db (name collection)) + (to-db-object document) + write-concern))) + +(defn ^clojure.lang.IPersistentMap save-and-return + "Like monger.collection/save-and-return but always takes a database as explicit argument" + ([^DB db ^String collection ^Map document] + (save-and-return ^DB db collection document ^WriteConcern monger.core/*mongodb-write-concern*)) + ([^DB db ^String collection ^Map document ^WriteConcern write-concern] + ;; see the comment in insert-and-return. Here we additionally need to make sure to not scrap the :_id key if + ;; it is already present. MK. + (let [doc (merge {:_id (ObjectId.)} document)] + (save db collection doc write-concern) + doc))) + +(defn ^WriteResult remove + "Like monger.collection/remove but always takes a database as explicit argument" + ([^DB db ^String collection] + (.remove (.getCollection db (name collection)) (to-db-object {}))) + ([^DB db ^String collection ^Map conditions] + (.remove (.getCollection db (name collection)) (to-db-object conditions)))) + +(defn ^WriteResult remove-by-id + "Like monger.collection/remove-by-id but always takes a database as explicit argument" + ([^DB db ^String collection id] + (check-not-nil! id "id must not be nil") + (let [coll (.getCollection db (name collection))] + (.remove coll (to-db-object {:_id id}))))) + +;; +;; monger.multi.collection/create-index +;; + +(defn create-index + "Like monger.collection/create-index but always takes a database as explicit argument" + ([^DB db ^String collection ^Map keys] + (.createIndex (.getCollection db (name collection)) (as-field-selector keys))) + ([^DB db ^String collection ^Map keys ^Map options] + (.createIndex (.getCollection db (name collection)) + (as-field-selector keys) + (to-db-object options)))) + +;; +;; monger.multi.collection/ensure-index +;; + +(defn ensure-index + "Like monger.collection/ensure-index but always takes a database as explicit argument" + ([^DB db ^String collection ^Map keys] + (.ensureIndex (.getCollection db (name collection)) (as-field-selector keys))) + ([^DB db ^String collection ^Map keys ^Map options] + (.ensureIndex (.getCollection db (name collection)) + (as-field-selector keys) + (to-db-object options))) + ([^DB db ^String collection ^Map keys ^String name ^Boolean unique?] + (.ensureIndex (.getCollection db (name collection)) + (as-field-selector keys) + name + unique?))) + +;; +;; monger.multi.collection/indexes-on +;; + +(defn indexes-on + "Like monger.collection/indexes-on but always takes a database as explicit argument" + [^DB db ^String collection] + (from-db-object (.getIndexInfo (.getCollection db (name collection))) true)) + + +;; +;; monger.multi.collection/drop-index +;; + +(defn drop-index + "Like monger.collection/drop-index but always takes a database as explicit argument" + ([^DB db ^String collection ^String idx-name] + (.dropIndex (.getCollection db (name collection)) idx-name))) + +(defn drop-indexes + "Like monger.collection/drop-indexes but always takes a database as explicit argument" + ([^DB db ^String collection] + (.dropIndexes (.getCollection db (name collection))))) + + +;; +;; monger.multi.collection/exists?, /create, /drop, /rename +;; + + +(defn exists? + "Like monger.collection/exists? but always takes a database as explicit argument" + ([^DB db ^String collection] + (.collectionExists db collection))) + +(defn create + "Like monger.collection/create but always takes a database as explicit argument" + ([^DB db ^String collection ^Map options] + (.createCollection db collection (to-db-object options)))) + +(defn drop + "Like monger.collection/drop but always takes a database as explicit argument" + ([^DB db ^String collection] + (.drop (.getCollection db (name collection))))) + +(defn rename + "Like monger.collection/rename but always takes a database as explicit argument" + ([^DB db ^String from, ^String to] + (.rename (.getCollection db from) to)) + ([^DB db ^String from ^String to ^Boolean drop-target] + (.rename (.getCollection db from) to drop-target))) + +;; +;; Map/Reduce +;; + +(defn map-reduce + "Like monger.collection/map-reduce but always takes a database as explicit argument" + ([^DB db ^String collection ^String js-mapper ^String js-reducer ^String output ^Map query] + (let [coll (.getCollection db (name collection))] + (.mapReduce coll js-mapper js-reducer output (to-db-object query)))) + ([^DB db ^String collection ^String js-mapper ^String js-reducer ^String output ^MapReduceCommand$OutputType output-type ^Map query] + (let [coll (.getCollection db (name collection))] + (.mapReduce coll js-mapper js-reducer output output-type (to-db-object query))))) + + +;; +;; monger.multi.collection/distinct +;; + +(defn distinct + "Like monger.collection/distinct but always takes a database as explicit argument" + ([^DB db ^String collection ^String key] + (.distinct (.getCollection db (name collection)) ^String (to-db-object key))) + ([^DB db ^String collection ^String key ^Map query] + (.distinct (.getCollection db (name collection)) ^String (to-db-object key) (to-db-object query)))) + diff --git a/test/monger/test/multi/find_test.clj b/test/monger/test/multi/find_test.clj new file mode 100644 index 0000000..5f86900 --- /dev/null +++ b/test/monger/test/multi/find_test.clj @@ -0,0 +1,145 @@ + +(ns monger.test.multi.find-test + (:import [com.mongodb WriteResult WriteConcern DBCursor DBObject DBRef] + org.bson.types.ObjectId + java.util.Date) + (:require [monger.core :as mg] + [monger.util :as mu] + [monger.multi.collection :as mgcol] + [monger.test.helper :as helper] + [monger.conversion :as mgcnv]) + (:use clojure.test + monger.operators + monger.conversion + monger.test.fixtures)) + +(helper/connect!) + + +(use-fixtures :each purge-people purge-docs purge-things purge-libraries) + +;; +;; find +;; + +(deftest find-full-document-when-collection-is-empty + (let [db (mg/get-db "monger-test") + collection "docs" + cursor (mgcol/find db collection)] + (is (empty? (iterator-seq cursor))))) + +(deftest find-document-seq-when-collection-is-empty + (let [db (mg/get-db "monger-test") + collection "docs"] + (is (empty? (mgcol/find-seq db collection))))) + +(deftest find-multiple-documents-when-collection-is-empty + (let [db (mg/get-db "monger-test") + collection "libraries"] + (is (empty? (mgcol/find db collection { :language "Scala" }))))) + +(deftest find-multiple-maps-when-collection-is-empty + (let [db (mg/get-db "monger-test") + collection "libraries"] + (is (empty? (mgcol/find-maps db collection { :language "Scala" }))))) + +(deftest find-multiple-documents-by-regex + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Java", :name "nhibernate" } + { :language "JavaScript", :name "sprout-core" }]) + (is (= 2 (monger.core/count (mgcol/find db collection { :language #"Java*" })))))) + +(deftest find-multiple-documents + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" } + { :language "Clojure", :name "incanter" } + { :language "Scala", :name "akka" }]) + (is (= 1 (monger.core/count (mgcol/find db collection { :language "Scala" })))) + (is (= 3 (.count (mgcol/find db collection { :language "Clojure" })))) + (is (empty? (mgcol/find db collection { :language "Java" }))))) + + +(deftest find-document-specify-fields + (let [db (mg/get-db "monger-test") + collection "libraries" + _ (mgcol/insert db collection { :language "Clojure", :name "monger" }) + result (mgcol/find db collection { :language "Clojure"} [:language])] + (is (= (seq [:_id :language]) (keys (mgcnv/from-db-object (.next result) true)))))) + +(deftest find-and-iterate-over-multiple-documents-the-hard-way + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" } + { :language "Clojure", :name "incanter" } + { :language "Scala", :name "akka" }]) + (doseq [doc (take 3 (map (fn [dbo] + (mgcnv/from-db-object dbo true)) + (mgcol/find-seq db collection { :language "Clojure" })))] + (is (= "Clojure" (:language doc)))))) + +(deftest find-and-iterate-over-multiple-documents + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" } + { :language "Clojure", :name "incanter" } + { :language "Scala", :name "akka" }]) + (doseq [doc (take 3 (mgcol/find-maps db collection { :language "Clojure" }))] + (is (= "Clojure" (:language doc)))))) + + +(deftest find-multiple-maps + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" } + { :language "Clojure", :name "incanter" } + { :language "Scala", :name "akka" }]) + (is (= 1 (count (mgcol/find-maps db collection { :language "Scala" })))) + (is (= 3 (count (mgcol/find-maps db collection { :language "Clojure" })))) + (is (empty? (mgcol/find-maps db collection { :language "Java" }))) + (is (empty? (mgcol/find-maps db collection { :language "Java" } [:language :name]))))) + + + +(deftest find-multiple-partial-documents + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" } + { :language "Clojure", :name "incanter" } + { :language "Scala", :name "akka" }]) + (let [scala-libs (mgcol/find db collection { :language "Scala" } [:name]) + clojure-libs (mgcol/find db collection { :language "Clojure"} [:language])] + (is (= 1 (.count scala-libs))) + (is (= 3 (.count clojure-libs))) + (doseq [i clojure-libs] + (let [doc (mgcnv/from-db-object i true)] + (is (= (:language doc) "Clojure")))) + (is (empty? (mgcol/find db collection { :language "Erlang" } [:name])))))) + +(deftest finds-one-as-map + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" }]) + (let [res (mgcol/find-one-as-map db collection { :name "langohr" })] + (is (map? res)) + (is (= "langohr" (:name res))) + (is (= "Clojure" (:language res)))) + (is (= 2 (count (mgcol/find-one-as-map db collection { :name "langohr" } [:name])))) + (is (= "langohr" (get (mgcol/find-one-as-map db collection { :name "langohr" } [:name] false) "name"))))) + +(deftest find-and-modify + (let [db (mg/get-db "monger-test") + collection "libraries"] + (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } + { :language "Clojure", :name "langohr" }]))) + +(run-tests) + diff --git a/test/monger/test/multi/inserting_test.clj b/test/monger/test/multi/inserting_test.clj index bebedef..01d9532 100644 --- a/test/monger/test/multi/inserting_test.clj +++ b/test/monger/test/multi/inserting_test.clj @@ -86,3 +86,104 @@ result (mc/insert db "widgets" doc)] (is (= (sort ["kw1" "kw2"]) (sort (get-in (mc/find-map-by-id db collection id) [:keyword1 :keyword2])))))) + +(defrecord Metrics + [rps eps]) + +(deftest insert-a-document-with-clojure-record-in-it + (let [db (mg/get-db "altdb") + collection "widgets" + id (ObjectId.) + doc {:record (Metrics. 10 20) "_id" id} + result (mc/insert db "widgets" doc)] + (is (= {:rps 10 :eps 20} (:record (mc/find-map-by-id db collection id)))))) + +(deftest test-insert-a-document-with-dbref + (let [db (mg/get-db "altdb")] + (mc/remove db "widgets") + (mc/remove db "owners") + (let [coll1 "widgets" + coll2 "owners" + oid (ObjectId.) + joe (mc/insert db "owners" {:name "Joe" :_id oid}) + dbref (DBRef. (mg/current-db) coll2 oid)] + (mc/insert coll1 {:type "pentagon" :owner dbref}) + (let [fetched (mc/find-one-as-map db coll1 {:type "pentagon"}) + fo (:owner fetched)] + (is (= {:_id oid :name "Joe"} (from-db-object @fo true))))))) + + +;; +;; insert-and-return +;; + +(deftest insert-and-return-a-basic-document-without-id-and-with-default-write-concern + (let [db (mg/get-db "altdb") + collection "people" + doc {:name "Joe" :age 30} + result (mc/insert-and-return db :people doc)] + (is (= (:name doc) + (:name result))) + (is (= (:age doc) + (:age result))) + (is (:_id result)) + (is (= 1 (mc/count collection))))) + +(deftest insert-and-return-a-basic-document-without-id-but-with-a-write-concern + (let [db (mg/get-db "altdb") + collection "people" + doc {:name "Joe" :age 30 :ratio 3/4} + result (mc/insert-and-return db "people" doc WriteConcern/FSYNC_SAFE)] + (is (= (:name doc) + (:name result))) + (is (= (:age doc) + (:age result))) + (is (= (:ratio doc) + (:ratio result))) + (is (:_id result)) + (is (= 1 (mc/count collection))))) + +(deftest insert-and-return-with-a-provided-id + (let [db (mg/get-db "altdb") + collection "people" + oid (ObjectId.) + doc {:name "Joe" :age 30 :_id oid} + result (mc/insert-and-return db :people doc)] + (is (= (:_id result) (:_id doc) oid)) + (is (= 1 (mc/count collection))))) + + +;; +;; insert-batch +;; + +(deftest insert-a-batch-of-basic-documents-without-ids-and-with-default-write-concern + (let [db (mg/get-db "altdb") + collection "people" + docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]] + (is (monger.result/ok? (mc/insert-batch db "people" docs))) + (is (= 2 (mc/count collection))))) + +(deftest insert-a-batch-of-basic-documents-without-ids-and-with-explicit-write-concern + (let [db (mg/get-db "altdb") + collection "people" + docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]] + (is (monger.result/ok? (mc/insert-batch db "people" docs WriteConcern/NORMAL))) + (is (= 2 (mc/count collection))))) + +(deftest insert-a-batch-of-basic-documents-with-explicit-database-without-ids-and-with-explicit-write-concern + (let [db (mg/get-db "altdb") + collection "people" + docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]] + (dotimes [n 44] + (is (monger.result/ok? (mc/insert-batch db "people" docs WriteConcern/NORMAL)))) + (is (= 88 (mc/count collection))))) + +(deftest insert-a-batch-of-basic-documents-from-a-lazy-sequence + (let [db (mg/get-db "altdb") + collection "people" + numbers (range 0 1000)] + (is (monger.result/ok? (mc/insert-batch db "people" (map (fn [^long l] + {:n l}) + numbers)))) + (is (= (count numbers) (mc/count collection))))) From 6a9cb9f1a37f5d21e9e3b4e4c47d709a4ea37430 Mon Sep 17 00:00:00 2001 From: Erik Bakstad Date: Thu, 20 Jun 2013 19:11:52 +0200 Subject: [PATCH 2/5] Don't run fin_test on ns load --- test/monger/test/multi/find_test.clj | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/monger/test/multi/find_test.clj b/test/monger/test/multi/find_test.clj index 5f86900..aaafe38 100644 --- a/test/monger/test/multi/find_test.clj +++ b/test/monger/test/multi/find_test.clj @@ -141,5 +141,3 @@ (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" }]))) -(run-tests) - From fd5e04109950a0847ad60d45dc041e696561921c Mon Sep 17 00:00:00 2001 From: Erik Bakstad Date: Thu, 20 Jun 2013 19:41:02 +0200 Subject: [PATCH 3/5] Fixed test issues when running all tests --- test/monger/test/multi/find_test.clj | 32 +++++++++++++---------- test/monger/test/multi/inserting_test.clj | 16 ++++++------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/test/monger/test/multi/find_test.clj b/test/monger/test/multi/find_test.clj index aaafe38..af5955b 100644 --- a/test/monger/test/multi/find_test.clj +++ b/test/monger/test/multi/find_test.clj @@ -15,36 +15,40 @@ (helper/connect!) +(defn drop-altdb + [f] + (mg/drop-db "altdb") + (f)) -(use-fixtures :each purge-people purge-docs purge-things purge-libraries) +(use-fixtures :each drop-altdb) ;; ;; find ;; (deftest find-full-document-when-collection-is-empty - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "docs" cursor (mgcol/find db collection)] (is (empty? (iterator-seq cursor))))) (deftest find-document-seq-when-collection-is-empty - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "docs"] (is (empty? (mgcol/find-seq db collection))))) (deftest find-multiple-documents-when-collection-is-empty - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (is (empty? (mgcol/find db collection { :language "Scala" }))))) (deftest find-multiple-maps-when-collection-is-empty - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (is (empty? (mgcol/find-maps db collection { :language "Scala" }))))) (deftest find-multiple-documents-by-regex - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Java", :name "nhibernate" } @@ -52,7 +56,7 @@ (is (= 2 (monger.core/count (mgcol/find db collection { :language #"Java*" })))))) (deftest find-multiple-documents - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" } @@ -64,14 +68,14 @@ (deftest find-document-specify-fields - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries" _ (mgcol/insert db collection { :language "Clojure", :name "monger" }) result (mgcol/find db collection { :language "Clojure"} [:language])] (is (= (seq [:_id :language]) (keys (mgcnv/from-db-object (.next result) true)))))) (deftest find-and-iterate-over-multiple-documents-the-hard-way - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" } @@ -83,7 +87,7 @@ (is (= "Clojure" (:language doc)))))) (deftest find-and-iterate-over-multiple-documents - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" } @@ -94,7 +98,7 @@ (deftest find-multiple-maps - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" } @@ -108,7 +112,7 @@ (deftest find-multiple-partial-documents - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" } @@ -124,7 +128,7 @@ (is (empty? (mgcol/find db collection { :language "Erlang" } [:name])))))) (deftest finds-one-as-map - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" }]) @@ -136,7 +140,7 @@ (is (= "langohr" (get (mgcol/find-one-as-map db collection { :name "langohr" } [:name] false) "name"))))) (deftest find-and-modify - (let [db (mg/get-db "monger-test") + (let [db (mg/get-db "altdb") collection "libraries"] (mgcol/insert-batch db collection [{ :language "Clojure", :name "monger" } { :language "Clojure", :name "langohr" }]))) diff --git a/test/monger/test/multi/inserting_test.clj b/test/monger/test/multi/inserting_test.clj index 01d9532..4bdd63c 100644 --- a/test/monger/test/multi/inserting_test.clj +++ b/test/monger/test/multi/inserting_test.clj @@ -107,7 +107,7 @@ oid (ObjectId.) joe (mc/insert db "owners" {:name "Joe" :_id oid}) dbref (DBRef. (mg/current-db) coll2 oid)] - (mc/insert coll1 {:type "pentagon" :owner dbref}) + (mc/insert db coll1 {:type "pentagon" :owner dbref}) (let [fetched (mc/find-one-as-map db coll1 {:type "pentagon"}) fo (:owner fetched)] (is (= {:_id oid :name "Joe"} (from-db-object @fo true))))))) @@ -127,7 +127,7 @@ (is (= (:age doc) (:age result))) (is (:_id result)) - (is (= 1 (mc/count collection))))) + (is (= 1 (mc/count db collection))))) (deftest insert-and-return-a-basic-document-without-id-but-with-a-write-concern (let [db (mg/get-db "altdb") @@ -141,7 +141,7 @@ (is (= (:ratio doc) (:ratio result))) (is (:_id result)) - (is (= 1 (mc/count collection))))) + (is (= 1 (mc/count db collection))))) (deftest insert-and-return-with-a-provided-id (let [db (mg/get-db "altdb") @@ -150,7 +150,7 @@ doc {:name "Joe" :age 30 :_id oid} result (mc/insert-and-return db :people doc)] (is (= (:_id result) (:_id doc) oid)) - (is (= 1 (mc/count collection))))) + (is (= 1 (mc/count db collection))))) ;; @@ -162,14 +162,14 @@ collection "people" docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]] (is (monger.result/ok? (mc/insert-batch db "people" docs))) - (is (= 2 (mc/count collection))))) + (is (= 2 (mc/count db collection))))) (deftest insert-a-batch-of-basic-documents-without-ids-and-with-explicit-write-concern (let [db (mg/get-db "altdb") collection "people" docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]] (is (monger.result/ok? (mc/insert-batch db "people" docs WriteConcern/NORMAL))) - (is (= 2 (mc/count collection))))) + (is (= 2 (mc/count db collection))))) (deftest insert-a-batch-of-basic-documents-with-explicit-database-without-ids-and-with-explicit-write-concern (let [db (mg/get-db "altdb") @@ -177,7 +177,7 @@ docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]] (dotimes [n 44] (is (monger.result/ok? (mc/insert-batch db "people" docs WriteConcern/NORMAL)))) - (is (= 88 (mc/count collection))))) + (is (= 88 (mc/count db collection))))) (deftest insert-a-batch-of-basic-documents-from-a-lazy-sequence (let [db (mg/get-db "altdb") @@ -186,4 +186,4 @@ (is (monger.result/ok? (mc/insert-batch db "people" (map (fn [^long l] {:n l}) numbers)))) - (is (= (count numbers) (mc/count collection))))) + (is (= (count numbers) (mc/count db collection))))) From 41c2aa748892cfbc8b93a4f0d67ad9416aa2b1b9 Mon Sep 17 00:00:00 2001 From: Erik Bakstad Date: Thu, 20 Jun 2013 19:56:26 +0200 Subject: [PATCH 4/5] Added multi.collection-tests --- test/monger/test/multi/collection_test.clj | 132 +++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 test/monger/test/multi/collection_test.clj diff --git a/test/monger/test/multi/collection_test.clj b/test/monger/test/multi/collection_test.clj new file mode 100644 index 0000000..dc42d3e --- /dev/null +++ b/test/monger/test/multi/collection_test.clj @@ -0,0 +1,132 @@ +(set! *warn-on-reflection* true) + +(ns monger.test.multi.collection-test + (:import [com.mongodb WriteResult WriteConcern DBCursor DBObject MapReduceOutput MapReduceCommand MapReduceCommand$OutputType] + org.bson.types.ObjectId + java.util.Date) + (:require [monger.core :as mg] + [monger.multi.collection :as mc] + [monger.result :as mgres] + [monger.test.helper :as helper]) + (:use clojure.test + monger.operators + monger.test.fixtures)) + +(helper/connect!) + +(defn drop-altdb + [f] + (mg/drop-db "altdb") + (f)) + +(use-fixtures :each drop-altdb) + +(deftest get-collection-size + (let [db (mg/get-db "altdb") + collection "things"] + (is (= 0 (mc/count db collection))) + (mc/insert-batch db collection [{:language "Clojure" :name "langohr"} + {:language "Clojure" :name "monger"} + {:language "Clojure" :name "incanter"} + {:language "Scala" :name "akka"}]) + (is (= 4 (mc/count db collection))) + (is (mc/any? db collection)) + (is (= 3 (mc/count db collection {:language "Clojure"}))) + (is (mc/any? db collection {:language "Clojure"})) + (is (= 1 (mc/count db collection {:language "Scala" }))) + (is (mc/any? db collection {:language "Scala"})) + (is (= 0 (mc/count db collection {:language "Python" }))) + (is (not (mc/any? db collection {:language "Python"}))))) + +(deftest remove-all-documents-from-collection + (let [db (mg/get-db "altdb") + collection "libraries"] + (mc/insert-batch db collection [{:language "Clojure" :name "monger"} + {:language "Clojure" :name "langohr"} + {:language "Clojure" :name "incanter"} + {:language "Scala" :name "akka"}]) + (is (= 4 (mc/count db collection))) + (mc/remove db collection) + (is (= 0 (mc/count db collection))))) + +(deftest remove-some-documents-from-collection + (let [db (mg/get-db "altdb") + collection "libraries"] + (mc/insert-batch db collection [{:language "Clojure" :name "monger"} + {:language "Clojure" :name "langohr"} + {:language "Clojure" :name "incanter"} + {:language "Scala" :name "akka"}]) + (is (= 4 (mc/count db collection))) + (mc/remove db collection {:language "Clojure"}) + (is (= 1 (mc/count db collection))))) + +(deftest remove-a-single-document-from-collection + (let [db (mg/get-db "altdb") + collection "libraries" + oid (ObjectId.)] + (mc/insert-batch db collection [{:language "Clojure" :name "monger" :_id oid}]) + (mc/remove-by-id db collection oid) + (is (= 0 (mc/count db collection))) + (is (nil? (mc/find-by-id db collection oid))))) + +(deftest checking-for-collection-existence-when-it-does-not-exist + (let [db (mg/get-db "altdb") + collection "widgets"] + (mc/drop db collection) + (is (false? (mc/exists? db collection))))) + +(deftest checking-for-collection-existence-when-it-does-exist + (let [db (mg/get-db "altdb") + collection "widgets"] + (mc/drop db collection) + (mc/insert-batch db collection [{:name "widget1"} + {:name "widget2"}]) + (is (mc/exists? db collection)) + (mc/drop db collection) + (is (false? (mc/exists? db collection))) + (mc/create db "widgets" {:capped true :size 100000 :max 10}) + (is (mc/exists? db collection)) + (mc/rename db collection "gadgets") + (is (not (mc/exists? db collection))) + (is (mc/exists? db "gadgets")) + (mc/drop db "gadgets"))) + +(deftest test-any-on-empty-collection + (let [db (mg/get-db "altdb") + collection "things"] + (is (not (mc/any? db collection))))) + +(deftest test-any-on-non-empty-collection + (let [db (mg/get-db "altdb") + collection "things" + _ (mc/insert db collection {:language "Clojure" :name "langohr"})] + (is (mc/any? db "things")) + (is (mc/any? db "things" {:language "Clojure"})))) + +(deftest test-empty-on-empty-collection + (let [db (mg/get-db "altdb") + collection "things"] + (is (mc/empty? db collection)) + (is (mc/empty? db collection)))) + +(deftest test-empty-on-non-empty-collection + (let [db (mg/get-db "altdb") + collection "things" + _ (mc/insert db collection {:language "Clojure" :name "langohr"})] + (is (not (mc/empty? db "things"))))) + +(deftest test-distinct-values + (let [db (mg/get-db "altdb") + collection "widgets" + batch [{:state "CA" :quantity 1 :price 199.00} + {:state "NY" :quantity 2 :price 199.00} + {:state "NY" :quantity 1 :price 299.00} + {:state "IL" :quantity 2 :price 11.50 } + {:state "CA" :quantity 2 :price 2.95 } + {:state "IL" :quantity 3 :price 5.50 }]] + (mc/insert-batch db collection batch) + (is (= ["CA" "IL" "NY"] (sort (mc/distinct db collection :state {})))) + (is (= ["CA" "NY"] (sort (mc/distinct db collection :state {:price {$gt 100.00}})))))) + + +(run-tests) From 0a03ec1bf89a5a233a155497b8a545cd54837303 Mon Sep 17 00:00:00 2001 From: Erik Bakstad Date: Sat, 22 Jun 2013 20:20:59 +0200 Subject: [PATCH 5/5] Added rest of tests. Fixes #53 --- .../test/multi/atomic_modifiers_test.clj | 407 ++++++++++++++++++ test/monger/test/multi/indexing_test.clj | 57 +++ test/monger/test/multi/updating_test.clj | 183 ++++++++ 3 files changed, 647 insertions(+) create mode 100644 test/monger/test/multi/atomic_modifiers_test.clj create mode 100644 test/monger/test/multi/indexing_test.clj create mode 100644 test/monger/test/multi/updating_test.clj diff --git a/test/monger/test/multi/atomic_modifiers_test.clj b/test/monger/test/multi/atomic_modifiers_test.clj new file mode 100644 index 0000000..28247f7 --- /dev/null +++ b/test/monger/test/multi/atomic_modifiers_test.clj @@ -0,0 +1,407 @@ +(set! *warn-on-reflection* true) + +(ns monger.test.multi.atomic-modifiers-test + (:import [com.mongodb WriteResult WriteConcern DBCursor DBObject] + [org.bson.types ObjectId] + [java.util Date]) + (:require [monger.core :as mg] + [monger core util] + [monger.multi.collection :as mgcol] + [monger.result :as mgres] + [monger.test.helper :as helper]) + (:use [clojure.test] + [monger.operators] + [monger.test.fixtures])) + +(helper/connect!) + +(defn drop-altdb + [f] + (mg/drop-db "altdb") + (f)) + +(use-fixtures :each drop-altdb) + +;; +;; $inc +;; + +(deftest increment-a-single-existing-field-using-$inc-modifier + (let [db (mg/get-db "altdb") + coll "scores" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :username "l33r0y" :score 100 }) + (mgcol/update db coll { :_id oid } { $inc { :score 20 } }) + (is (= 120 (:score (mgcol/find-map-by-id db coll oid)))))) + +(deftest set-a-single-non-existing-field-using-$inc-modifier + (let [db (mg/get-db "altdb") + coll "scores" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :username "l33r0y" }) + (mgcol/update db coll { :_id oid } { $inc { :score 30 } }) + (is (= 30 (:score (mgcol/find-map-by-id db coll oid)))))) + + +(deftest increment-multiple-existing-fields-using-$inc-modifier + (let [db (mg/get-db "altdb") + coll "scores" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :username "l33r0y" :score 100 :bonus 0 }) + (mgcol/update db coll { :_id oid } {$inc { :score 20 :bonus 10 } }) + (is (= { :_id oid :score 120 :bonus 10 :username "l33r0y" } (mgcol/find-map-by-id db coll oid))))) + + +(deftest increment-and-set-multiple-existing-fields-using-$inc-modifier + (let [db (mg/get-db "altdb") + coll "scores" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :username "l33r0y" :score 100 }) + (mgcol/update db coll { :_id oid } { $inc { :score 20 :bonus 10 } }) + (is (= { :_id oid :score 120 :bonus 10 :username "l33r0y" } (mgcol/find-map-by-id db coll oid))))) + + + +;; +;; $set +;; + +(deftest update-a-single-existing-field-using-$set-modifier + (let [db (mg/get-db "altdb") + coll "things" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :weight 10.0 }) + (mgcol/update db coll { :_id oid } { $set { :weight 20.5 } }) + (is (= 20.5 (:weight (mgcol/find-map-by-id db coll oid [:weight])))))) + +(deftest set-a-single-non-existing-field-using-$set-modifier + (let [db (mg/get-db "altdb") + coll "things" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :weight 10.0 }) + (mgcol/update db coll { :_id oid } { $set { :height 17.2 } }) + (is (= 17.2 (:height (mgcol/find-map-by-id db coll oid [:height])))))) + +(deftest update-multiple-existing-fields-using-$set-modifier + (let [db (mg/get-db "altdb") + coll "things" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :weight 10.0 :height 15.2 }) + (mgcol/update db coll { :_id oid } { $set { :weight 20.5 :height 25.6 } }) + (is (= { :_id oid :weight 20.5 :height 25.6 } (mgcol/find-map-by-id db coll oid [:weight :height]))))) + + +(deftest update-and-set-multiple-fields-using-$set-modifier + (let [db (mg/get-db "altdb") + coll "things" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :weight 10.0 }) + (mgcol/update db coll { :_id oid } {$set { :weight 20.5 :height 25.6 } }) + (is (= { :_id oid :weight 20.5 :height 25.6 } (mgcol/find-map-by-id db coll oid [:weight :height]))))) + + +;; +;; $unset +;; + +(deftest unset-a-single-existing-field-using-$unset-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :title "Document 1" :published true }) + (mgcol/update db coll { :_id oid } { $unset { :published 1 } }) + (is (= { :_id oid :title "Document 1" } (mgcol/find-map-by-id db coll oid))))) + + +(deftest unset-multiple-existing-fields-using-$unset-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :title "Document 1" :published true :featured true }) + (mgcol/update db coll { :_id oid } { $unset { :published 1 :featured true } }) + (is (= { :_id oid :title "Document 1" } (mgcol/find-map-by-id db coll oid))))) + + +(deftest unsetting-an-unexisting-field-using-$unset-modifier-is-not-considered-an-issue + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :title "Document 1" :published true }) + (is (mgres/ok? (mgcol/update db coll { :_id oid } { $unset { :published 1 :featured true } }))) + (is (= { :_id oid :title "Document 1" } (mgcol/find-map-by-id db coll oid))))) + +;; +;; $setOnInsert +;; + +(deftest setOnInsert-in-upsert-for-non-existing-document + (let [db (mg/get-db "altdb") + coll "docs" + now 456 + oid (ObjectId.)] + (mgcol/find-and-modify db coll {:_id oid} {$set {:lastseen now} $setOnInsert {:firstseen now}} :upsert true) + (is (= { :_id oid :lastseen now :firstseen now} (mgcol/find-map-by-id db coll oid))))) + +(deftest setOnInsert-in-upsert-for-existing-document + (let [db (mg/get-db "altdb") + coll "docs" + before 123 + now 456 + oid (ObjectId.)] + (mgcol/insert db coll { :_id oid :firstseen before :lastseen before}) + (mgcol/find-and-modify db coll {:_id oid} {$set {:lastseen now} $setOnInsert {:firstseen now}} :upsert true) + (is (= { :_id oid :lastseen now :firstseen before} (mgcol/find-map-by-id db coll oid))))) + +;; +;; $push +;; + +(deftest initialize-an-array-using-$push-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$push modifier appends value to field"] + (mgcol/insert db coll { :_id oid :title title }) + (mgcol/update db coll { :_id oid } { $push { :tags "modifiers" } }) + (is (= { :_id oid :title title :tags ["modifiers"] } (mgcol/find-map-by-id db coll oid))))) + +(deftest add-value-to-an-existing-array-using-$push-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$push modifier appends value to field"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb"] }) + (mgcol/update db coll { :_id oid } { $push { :tags "modifiers" } }) + (is (= { :_id oid :title title :tags ["mongodb" "modifiers"] } (mgcol/find-map-by-id db coll oid))))) + + +;; this is a common mistake, I leave it here to demonstrate it. You almost never +;; actually want to do this! What you really want is to use $pushAll instead of $push. MK. +(deftest add-array-value-to-an-existing-array-using-$push-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$push modifier appends value to field"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb"] }) + (mgcol/update db coll { :_id oid } { $push { :tags ["modifiers" "operators"] } }) + (is (= { :_id oid :title title :tags ["mongodb" ["modifiers" "operators"]] } (mgcol/find-map-by-id db coll oid))))) + + + +(deftest double-add-value-to-an-existing-array-using-$push-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$push modifier appends value to field"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb"] }) + (mgcol/update db coll { :_id oid } { $push { :tags "modifiers" } }) + (mgcol/update db coll { :_id oid } { $push { :tags "modifiers" } }) + (is (= { :_id oid :title title :tags ["mongodb" "modifiers" "modifiers"] } (mgcol/find-map-by-id db coll oid))))) + +;; +;; $pushAll +;; + +(deftest initialize-an-array-using-$pushAll-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pushAll modifier appends multiple values to field"] + (mgcol/insert db coll { :_id oid :title title }) + (mgcol/update db coll { :_id oid } { $pushAll { :tags ["mongodb" "docs"] } }) + (is (= { :_id oid :title title :tags ["mongodb" "docs"] } (mgcol/find-map-by-id db coll oid))))) + +(deftest add-value-to-an-existing-array-using-$pushAll-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pushAll modifier appends multiple values to field"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb"] }) + (mgcol/update db coll { :_id oid } { $pushAll { :tags ["modifiers" "docs"] } }) + (is (= { :_id oid :title title :tags ["mongodb" "modifiers" "docs"] } (mgcol/find-map-by-id db coll oid))))) + + +(deftest double-add-value-to-an-existing-array-using-$pushAll-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pushAll modifier appends multiple values to field"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb" "docs"] }) + (mgcol/update db coll { :_id oid } { $pushAll { :tags ["modifiers" "docs"] } }) + (is (= { :_id oid :title title :tags ["mongodb" "docs" "modifiers" "docs"] } (mgcol/find-map-by-id db coll oid))))) + + +;; +;; $addToSet +;; + +(deftest initialize-an-array-using-$addToSet-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$addToSet modifier appends value to field unless it is already there"] + (mgcol/insert db coll { :_id oid :title title }) + (mgcol/update db coll { :_id oid } { $addToSet { :tags "modifiers" } }) + (is (= { :_id oid :title title :tags ["modifiers"] } (mgcol/find-map-by-id db coll oid))))) + +(deftest add-value-to-an-existing-array-using-$addToSet-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$addToSet modifier appends value to field unless it is already there"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb"] }) + (mgcol/update db coll { :_id oid } { $addToSet { :tags "modifiers" } }) + (is (= { :_id oid :title title :tags ["mongodb" "modifiers"] } (mgcol/find-map-by-id db coll oid))))) + + +(deftest double-add-value-to-an-existing-array-using-$addToSet-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$addToSet modifier appends value to field unless it is already there"] + (mgcol/insert db coll { :_id oid :title title :tags ["mongodb"] }) + (mgcol/update db coll { :_id oid } { $addToSet { :tags "modifiers" } }) + (mgcol/update db coll { :_id oid } { $addToSet { :tags "modifiers" } }) + (is (= { :_id oid :title title :tags ["mongodb" "modifiers"] } (mgcol/find-map-by-id db coll oid))))) + + +;; +;; $pop +;; + +(deftest pop-last-value-in-the-array-using-$pop-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pop modifier removes last or first value in the array"] + (mgcol/insert db coll { :_id oid :title title :tags ["products" "apple" "reviews"] }) + (mgcol/update db coll { :_id oid } { $pop { :tags 1 } }) + (is (= { :_id oid :title title :tags ["products" "apple"] } (mgcol/find-map-by-id db coll oid))))) + +(deftest unshift-first-value-in-the-array-using-$pop-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pop modifier removes last or first value in the array"] + (mgcol/insert db coll { :_id oid :title title :tags ["products" "apple" "reviews"] }) + (mgcol/update db coll { :_id oid } { $pop { :tags -1 } }) + (is (= { :_id oid :title title :tags ["apple" "reviews"] } (mgcol/find-map-by-id db coll oid))))) + +(deftest pop-last-values-from-multiple-arrays-using-$pop-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pop modifier removes last or first value in the array"] + (mgcol/insert db coll { :_id oid :title title :tags ["products" "apple" "reviews"] :categories ["apple" "reviews" "drafts"] }) + (mgcol/update db coll { :_id oid } { $pop { :tags 1 :categories 1 } }) + (is (= { :_id oid :title title :tags ["products" "apple"] :categories ["apple" "reviews"] } (mgcol/find-map-by-id db coll oid))))) + + +;; +;; $pull +;; + +(deftest remove-all-value-entries-from-array-using-$pull-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pull modifier removes all value entries in the array"] + (mgcol/insert db coll { :_id oid :title title :measurements [1.0 1.2 1.2 1.2 1.1 1.1 1.2 1.3 1.0] }) + (mgcol/update db coll { :_id oid } { $pull { :measurements 1.2 } }) + (is (= { :_id oid :title title :measurements [1.0 1.1 1.1 1.3 1.0] } (mgcol/find-map-by-id db coll oid))))) + +(deftest remove-all-value-entries-from-array-using-$pull-modifier-based-on-a-condition + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pull modifier removes all value entries in the array"] + (mgcol/insert db coll { :_id oid :title title :measurements [1.0 1.2 1.2 1.2 1.1 1.1 1.2 1.3 1.0] }) + (mgcol/update db coll { :_id oid } { $pull { :measurements { $gte 1.2 } } }) + (is (= { :_id oid :title title :measurements [1.0 1.1 1.1 1.0] } (mgcol/find-map-by-id db coll oid))))) +;; +;; $pullAll +;; + +(deftest remove-all-value-entries-from-array-using-$pullAll-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$pullAll modifier removes entries of multiple values in the array"] + (mgcol/insert db coll { :_id oid :title title :measurements [1.0 1.2 1.2 1.2 1.1 1.1 1.2 1.3 1.0] }) + (mgcol/update db coll { :_id oid } { $pullAll { :measurements [1.0 1.1 1.2] } }) + (is (= { :_id oid :title title :measurements [1.3] } (mgcol/find-map-by-id db coll oid))))) + + +;; +;; $rename +;; + +(deftest rename-a-single-field-using-$rename-modifier + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + title "$rename renames fields" + v [1.0 1.2 1.2 1.2 1.1 1.1 1.2 1.3 1.0]] + (mgcol/insert db coll { :_id oid :title title :measurements v }) + (mgcol/update db coll { :_id oid } { $rename { :measurements "results" } }) + (is (= { :_id oid :title title :results v } (mgcol/find-map-by-id db coll oid))))) + + +;; +;; find-and-modify +;; + +(deftest find-and-modify-a-single-document + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + doc {:_id oid :name "Sophie Bangs" :level 42} + conditions {:name "Sophie Bangs"} + update {$inc {:level 1}}] + (mgcol/insert db coll doc) + (let [res (mgcol/find-and-modify db 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 [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + doc {:_id oid :name "Sophie Bangs" :level 42} + conditions {:name "Sophie Bangs"}] + (mgcol/insert db coll doc) + (let [res (mgcol/find-and-modify db coll conditions {} :remove true)] + (is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42})) + (is (empty? (mgcol/find-maps db coll conditions)))))) + + +(deftest find-and-modify-upsert-a-document + (testing "case 1" + (let [db (mg/get-db "altdb") + coll "docs" + oid (ObjectId.) + doc {:_id oid :name "Sophie Bangs" :level 42}] + (let [res (mgcol/find-and-modify db coll doc doc :upsert true)] + (is (empty? res)) + (is (select-keys (mgcol/find-map-by-id db coll oid) [:name :level]) (dissoc doc :_id))))) + (testing "case 2" + (let [db (mg/get-db "altdb") + coll "docs" + query {:name "Sophie Bangs"} + doc (merge query {:level 42})] + (let [res (mgcol/find-and-modify db coll query doc :upsert true :return-new true)] + (is (:_id res)) + (is (select-keys (mgcol/find-map-by-id db coll (:_id res)) [:name :level]) doc))))) + + +(deftest find-and-modify-after-sort + (let [db (mg/get-db "altdb") + 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 db coll [doc1 doc2]) + (let [res (mgcol/find-and-modify db coll doc {$inc {:level 1}} :sort {:level -1})] + (is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42}))))) diff --git a/test/monger/test/multi/indexing_test.clj b/test/monger/test/multi/indexing_test.clj new file mode 100644 index 0000000..38540ac --- /dev/null +++ b/test/monger/test/multi/indexing_test.clj @@ -0,0 +1,57 @@ +(ns monger.test.multi.indexing-test + (:import org.bson.types.ObjectId + java.util.Date) + (:require [monger.core :as mg] + [monger.multi.collection :as mc] + [monger.test.helper :as helper] + monger.joda-time) + (:use clojure.test + monger.test.fixtures + [clj-time.core :only [now secs ago from-now]])) + +(helper/connect!) + +(defn drop-altdb + [f] + (mg/drop-db "altdb") + (f)) + +(use-fixtures :each drop-altdb) + +(deftest ^{:indexing true} test-creating-and-dropping-indexes + (let [db (mg/get-db "altdb") + collection "libraries"] + (mc/drop-indexes db collection) + (mc/create-index db collection { "language" 1 }) + (is (= "language_1" + (:name (second (mc/indexes-on db collection))))) + (mc/drop-index db collection "language_1") + (mc/create-index db collection ["language"]) + (mc/drop-index db collection "language_1") + (is (nil? (second (mc/indexes-on db collection)))) + (mc/ensure-index db collection (array-map "language" 1) {:unique true}) + (is (= "language_1" + (:name (second (mc/indexes-on db collection))))) + (mc/ensure-index db collection (array-map "language" 1)) + (mc/ensure-index db collection (array-map "language" 1) { :unique true }) + (mc/drop-indexes db collection))) + +(deftest ^{:indexing true :edge-features true :time-consuming true} test-ttl-collections + (let [db (mg/get-db "altdb") + coll "recent_events" + ttl 30 + sleep 120] + (mc/remove db coll) + (mc/ensure-index db coll (array-map :created-at 1) {:expireAfterSeconds ttl}) + (dotimes [i 100] + (mc/insert db coll {:type "signup" :created-at (-> i secs ago) :i i})) + (dotimes [i 100] + (mc/insert db coll {:type "signup" :created-at (-> i secs from-now) :i i})) + (is (= 200 (mc/count db coll {:type "signup"}))) + ;; sleep for 65 seconds. MongoDB 2.1.2 seems to run TTLMonitor once per minute, according to + ;; the log. MK. + (println (format "Now sleeping for %d seconds to test TTL collections!" sleep)) + (Thread/sleep (* sleep 1000)) + (println (format "Documents in the TTL collection: %d" (mc/count db coll {:type "signup"}))) + (is (< (mc/count db coll {:type "signup"}) 100)) + (mc/remove db coll))) diff --git a/test/monger/test/multi/updating_test.clj b/test/monger/test/multi/updating_test.clj new file mode 100644 index 0000000..6c4f37c --- /dev/null +++ b/test/monger/test/multi/updating_test.clj @@ -0,0 +1,183 @@ +(set! *warn-on-reflection* true) + +(ns monger.test.multi.updating-test + (:import [com.mongodb WriteResult WriteConcern DBCursor DBObject] + org.bson.types.ObjectId + java.util.Date) + (:require [monger.core :as mg] + [monger core util] + [monger.multi.collection :as mc] + [monger.result :as mr] + [monger.test.helper :as helper]) + (:use clojure.test + monger.operators + monger.test.fixtures + [monger.conversion :only [to-db-object]])) + +(helper/connect!) + +(defn drop-altdb + [f] + (mg/drop-db "altdb") + (f)) + +(use-fixtures :each drop-altdb) + +;; +;; update, save +;; + +(deftest ^{:updating true} update-document-by-id-without-upsert + (let [db (mg/get-db "altdb") + collection "libraries" + doc-id (monger.util/random-uuid) + date (Date.) + doc { :created-at date, :data-store "MongoDB", :language "Clojure", :_id doc-id } + modified-doc { :created-at date, :data-store "MongoDB", :language "Erlang", :_id doc-id }] + (mc/insert db collection doc) + (is (= (doc (mc/find-by-id db collection doc-id)))) + (mc/update db collection { :_id doc-id } { :language "Erlang" }) + (is (= (modified-doc (mc/find-by-id db collection doc-id)))))) + +(deftest ^{:updating true} update-document-by-id-without-upsert-using-update-by-id + (let [db (mg/get-db "altdb") + collection "libraries" + doc-id (monger.util/random-uuid) + date (Date.) + doc { :created-at date, :data-store "MongoDB", :language "Clojure", :_id doc-id } + modified-doc { :created-at date, :data-store "MongoDB", :language "Erlang", :_id doc-id }] + (mc/insert db collection doc) + (is (= (doc (mc/find-by-id db collection doc-id)))) + (mc/update-by-id db collection doc-id { :language "Erlang" }) + (is (= (modified-doc (mc/find-by-id db collection doc-id)))))) + +(deftest ^{:updating true} update-nested-document-fields-without-upsert-using-update-by-id + (let [db (mg/get-db "altdb") + collection "libraries" + doc-id (ObjectId.) + date (Date.) + doc { :created-at date :data-store "MongoDB" :language { :primary "Clojure" } :_id doc-id } + modified-doc { :created-at date :data-store "MongoDB" :language { :primary "Erlang" } :_id doc-id }] + (mc/insert db collection doc) + (is (= (doc (mc/find-by-id db collection doc-id)))) + (mc/update-by-id db collection doc-id { $set { "language.primary" "Erlang" }}) + (is (= (modified-doc (mc/find-by-id db collection doc-id)))))) + + +(deftest ^{:updating true} update-multiple-documents + (let [db (mg/get-db "altdb") + collection "libraries"] + (mc/insert db collection { :language "Clojure", :name "monger" }) + (mc/insert db collection { :language "Clojure", :name "langohr" }) + (mc/insert db collection { :language "Clojure", :name "incanter" }) + (mc/insert db collection { :language "Scala", :name "akka" }) + (is (= 3 (mc/count db collection { :language "Clojure" }))) + (is (= 1 (mc/count db collection { :language "Scala" }))) + (is (= 0 (mc/count db collection { :language "Python" }))) + (mc/update db collection { :language "Clojure" } { $set { :language "Python" } } :multi true) + (is (= 0 (mc/count db collection { :language "Clojure" }))) + (is (= 1 (mc/count db collection { :language "Scala" }))) + (is (= 3 (mc/count db collection { :language "Python" }))))) + + +(deftest ^{:updating true} save-a-new-document + (let [db (mg/get-db "altdb") + collection "people" + document {:name "Joe" :age 30}] + (is (mr/ok? (mc/save db "people" document))) + (is (= 1 (mc/count db collection))))) + +(deftest ^{:updating true} save-and-return-a-new-document + (let [db (mg/get-db "altdb") + collection "people" + document {:name "Joe" :age 30} + returned (mc/save-and-return db "people" document)] + (is (:_id returned)) + (is (= document (dissoc returned :_id))) + (is (= 1 (mc/count db collection))))) + + +(deftest ^{:updating true} save-a-new-basic-db-object + (let [db (mg/get-db "altdb") + collection "people" + doc (to-db-object {:name "Joe" :age 30})] + (is (nil? (monger.util/get-id doc))) + (mc/save db "people" doc WriteConcern/SAFE) + (is (not (nil? (monger.util/get-id doc)))))) + + + +(deftest ^{:updating true} update-an-existing-document-using-save + (let [db (mg/get-db "altdb") + collection "people" + doc-id "people-1" + document { :_id doc-id, :name "Joe", :age 30 }] + (is (mr/ok? (mc/insert db "people" document))) + (is (= 1 (mc/count db collection))) + (mc/save db collection { :_id doc-id, :name "Alan", :age 40 }) + (is (= 1 (mc/count db collection { :name "Alan", :age 40 }))))) + +(deftest ^{:updating true} update-an-existing-document-using-save-and-return + (let [db (mg/get-db "altdb") + collection "people" + document (mc/insert-and-return db "people" {:name "Joe" :age 30}) + doc-id (:_id document) + updated (mc/save-and-return db collection {:_id doc-id :name "Alan" :age 40})] + (is (= {:_id doc-id :name "Alan" :age 40} updated)) + (is (= 1 (mc/count db collection))) + (is (= 1 (mc/count db collection {:name "Alan" :age 40}))))) + + +(deftest ^{:updating true} set-an-attribute-on-existing-document-using-update + (let [db (mg/get-db "altdb") + collection "people" + doc-id (monger.util/object-id) + document { :_id doc-id, :name "Joe", :age 30 }] + (is (mr/ok? (mc/insert db "people" document))) + (is (= 1 (mc/count db collection))) + (is (= 0 (mc/count db collection { :has_kids true }))) + (mc/update db collection { :_id doc-id } { $set { :has_kids true } }) + (is (= 1 (mc/count db collection { :has_kids true }))))) + + +(deftest ^{:updating true} increment-multiple-fields-using-exists-operator-and-update + (let [db (mg/get-db "altdb") + collection "matches" + doc-id (monger.util/object-id) + document { :_id doc-id :abc 0 :def 10 }] + (mc/remove db collection) + (is (mr/ok? (mc/insert db collection document))) + (is (= 1 (mc/count db collection {:abc {$exists true} :def {$exists true}}))) + (mc/update db collection {:abc {$exists true} :def {$exists true}} {$inc {:abc 1 :def 0}}) + (is (= 1 (mc/count db collection { :abc 1 }))))) + + + +(deftest ^{:updating true} upsert-a-document-using-update + (let [db (mg/get-db "altdb") + collection "libraries" + doc-id (monger.util/random-uuid) + date (Date.) + doc { :created-at date, :data-store "MongoDB", :language "Clojure", :_id doc-id } + modified-doc { :created-at date, :data-store "MongoDB", :language "Erlang", :_id doc-id }] + (is (not (mr/updated-existing? (mc/update db collection { :language "Clojure" } doc :upsert true)))) + (is (= 1 (mc/count db collection))) + (is (mr/updated-existing? (mc/update db collection { :language "Clojure" } modified-doc :multi false :upsert true))) + (is (= 1 (mc/count db collection))) + (is (= (modified-doc (mc/find-by-id db collection doc-id)))) + (mc/remove db collection))) + +(deftest ^{:updating true} upsert-a-document-using-upsert + (let [db (mg/get-db "altdb") + collection "libraries" + doc-id (monger.util/random-uuid) + date (Date.) + doc {:created-at date :data-store "MongoDB" :language "Clojure" :_id doc-id} + modified-doc {:created-at date :data-store "MongoDB" :language "Erlang" :_id doc-id}] + (mc/remove db collection) + (is (not (mr/updated-existing? (mc/upsert db collection {:language "Clojure"} doc)))) + (is (= 1 (mc/count db collection))) + (is (mr/updated-existing? (mc/upsert db collection {:language "Clojure"} modified-doc :multi false))) + (is (= 1 (mc/count db collection))) + (is (= (modified-doc (mc/find-by-id db collection doc-id)))) + (mc/remove db collection)))