Initial work on monger.multi.collection
This commit is contained in:
parent
48be8602e3
commit
4ac8f8330a
8 changed files with 291 additions and 33 deletions
14
ChangeLog.md
14
ChangeLog.md
|
|
@ -1,5 +1,19 @@
|
||||||
## Changes between 1.5.0 and 1.6.0
|
## Changes between 1.5.0 and 1.6.0
|
||||||
|
|
||||||
|
### monger.multi.collection
|
||||||
|
|
||||||
|
`monger.multi.collection` is a new namespace with functions that are very similar to those
|
||||||
|
in the `monger.collection` namespace but always take a database reference as an explicit argument.
|
||||||
|
|
||||||
|
They are supposed to be used in cases when relying on `monger.core/*mongodb-database*` is not
|
||||||
|
enough.
|
||||||
|
|
||||||
|
|
||||||
|
## monger.core/drop-db
|
||||||
|
|
||||||
|
`monger.core/drop-db` is a new function that drops a database by name.
|
||||||
|
|
||||||
|
|
||||||
### One More Cache Implementation
|
### One More Cache Implementation
|
||||||
|
|
||||||
`monger.cache/db-aware-monger-cache-factory` will return a MongoDB-backed `clojure.core.cache`
|
`monger.cache/db-aware-monger-cache-factory` will return a MongoDB-backed `clojure.core.cache`
|
||||||
|
|
|
||||||
|
|
@ -9,36 +9,30 @@
|
||||||
;; the terms of this license.
|
;; the terms of this license.
|
||||||
;; You must not remove this notice, or any other, from this software.
|
;; You must not remove this notice, or any other, from this software.
|
||||||
|
|
||||||
(ns ^{:doc "Provides key functionality for interaction with MongoDB: inserting, querying, updating and deleting documents, performing Aggregation Framework
|
(ns monger.collection
|
||||||
queries, creating and dropping indexes, creating collections and more.
|
"Provides key functionality for interaction with MongoDB: inserting, querying, updating and deleting documents, performing Aggregation Framework
|
||||||
|
queries, creating and dropping indexes, creating collections and more.
|
||||||
|
|
||||||
For more advanced read queries, see monger.query.
|
For more advanced read queries, see monger.query.
|
||||||
|
|
||||||
Related documentation guides:
|
Related documentation guides:
|
||||||
|
|
||||||
* http://clojuremongodb.info/articles/getting_started.html
|
* http://clojuremongodb.info/articles/getting_started.html
|
||||||
* http://clojuremongodb.info/articles/inserting.html
|
* http://clojuremongodb.info/articles/inserting.html
|
||||||
* http://clojuremongodb.info/articles/querying.html
|
* http://clojuremongodb.info/articles/querying.html
|
||||||
* http://clojuremongodb.info/articles/updating.html
|
* http://clojuremongodb.info/articles/updating.html
|
||||||
* http://clojuremongodb.info/articles/deleting.html
|
* http://clojuremongodb.info/articles/deleting.html
|
||||||
* http://clojuremongodb.info/articles/aggregation.html"}
|
* http://clojuremongodb.info/articles/aggregation.html"
|
||||||
monger.collection
|
|
||||||
(:refer-clojure :exclude [find remove count drop distinct empty?])
|
(:refer-clojure :exclude [find remove count drop distinct empty?])
|
||||||
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor MapReduceCommand MapReduceCommand$OutputType]
|
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor MapReduceCommand MapReduceCommand$OutputType]
|
||||||
[java.util List Map]
|
[java.util List Map]
|
||||||
[clojure.lang IPersistentMap ISeq]
|
[clojure.lang IPersistentMap ISeq]
|
||||||
org.bson.types.ObjectId)
|
org.bson.types.ObjectId)
|
||||||
(:require [monger core result])
|
(:require monger.core
|
||||||
(:use [monger.conversion]))
|
monger.result)
|
||||||
|
(:use monger.conversion
|
||||||
|
monger.constraints))
|
||||||
|
|
||||||
;;
|
|
||||||
;; Implementation
|
|
||||||
;;
|
|
||||||
|
|
||||||
(definline check-not-nil!
|
|
||||||
[ref ^String message]
|
|
||||||
`(when (nil? ~ref)
|
|
||||||
(throw (IllegalArgumentException. ~message))))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
11
src/clojure/monger/constraints.clj
Normal file
11
src/clojure/monger/constraints.clj
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
(ns monger.constraints)
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; API
|
||||||
|
;;
|
||||||
|
|
||||||
|
(definline check-not-nil!
|
||||||
|
[ref ^String message]
|
||||||
|
`(when (nil? ~ref)
|
||||||
|
(throw (IllegalArgumentException. ~message))))
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
(extend-protocol ConvertToDBObject
|
(extend-protocol ConvertToDBObject
|
||||||
nil
|
nil
|
||||||
(to-db-object [input]
|
(to-db-object [input]
|
||||||
input)
|
nil)
|
||||||
|
|
||||||
String
|
String
|
||||||
(to-db-object [^String input]
|
(to-db-object [^String input]
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,12 @@
|
||||||
[]
|
[]
|
||||||
*mongodb-database*)
|
*mongodb-database*)
|
||||||
|
|
||||||
|
(defn drop-db
|
||||||
|
"Drops a database"
|
||||||
|
([^String db]
|
||||||
|
(.dropDatabase *mongodb-connection* db))
|
||||||
|
([^MongoClient conn ^String db]
|
||||||
|
(.dropDatabase conn db)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro with-connection
|
(defmacro with-connection
|
||||||
|
|
@ -243,7 +249,7 @@
|
||||||
Ordering of keys in the command document may matter. Please use sorted maps instead of map literals, for example:
|
Ordering of keys in the command document may matter. Please use sorted maps instead of map literals, for example:
|
||||||
(sorted-map geoNear \"bars\" :near 50 :test 430 :num 10)
|
(sorted-map geoNear \"bars\" :near 50 :test 430 :num 10)
|
||||||
|
|
||||||
For commonly used commands (distinct, count, map/reduce, etc), use monger/command and monger/collection functions such as
|
For commonly used commands (distinct, count, map/reduce, etc), use monger.command and monger.collection functions such as
|
||||||
/distinct, /count, /drop, /dropIndexes, and /mapReduce respectively."
|
/distinct, /count, /drop, /dropIndexes, and /mapReduce respectively."
|
||||||
([^Map cmd]
|
([^Map cmd]
|
||||||
(.command ^DB *mongodb-database* ^DBObject (to-db-object cmd)))
|
(.command ^DB *mongodb-database* ^DBObject (to-db-object cmd)))
|
||||||
|
|
|
||||||
139
src/clojure/monger/multi/collection.clj
Normal file
139
src/clojure/monger/multi/collection.clj
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
(ns monger.multi.collection
|
||||||
|
"Includes versions of key monger.collection functions that always take a database
|
||||||
|
as explicit argument instead of relying on monger.core/*mongodb-database*.
|
||||||
|
|
||||||
|
Use these functions when you need to work with multiple databases or manage database
|
||||||
|
and connection lifecycle explicitly."
|
||||||
|
(:refer-clojure :exclude [find remove count])
|
||||||
|
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor MapReduceCommand MapReduceCommand$OutputType]
|
||||||
|
[java.util List Map]
|
||||||
|
[clojure.lang IPersistentMap ISeq]
|
||||||
|
org.bson.types.ObjectId)
|
||||||
|
(:require monger.core
|
||||||
|
monger.result)
|
||||||
|
(:use monger.conversion
|
||||||
|
monger.constraints))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; API
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn ^WriteResult insert
|
||||||
|
"Like monger.collection/insert but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection document]
|
||||||
|
(.insert (.getCollection db (name collection))
|
||||||
|
(to-db-object document)
|
||||||
|
monger.core/*mongodb-write-concern*))
|
||||||
|
([^DB db ^String collection document ^WriteConcern concern]
|
||||||
|
(.insert (.getCollection db (name collection))
|
||||||
|
(to-db-object document)
|
||||||
|
concern)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn ^clojure.lang.IPersistentMap insert-and-return
|
||||||
|
"Like monger.collection/insert-and-return but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection document]
|
||||||
|
(let [doc (merge {:_id (ObjectId.)} document)]
|
||||||
|
(insert db collection doc monger.core/*mongodb-write-concern*)
|
||||||
|
doc))
|
||||||
|
([^DB db ^String collection document ^WriteConcern concern]
|
||||||
|
;; MongoDB Java driver will generate the _id and set it but it tries to mutate the inserted DBObject
|
||||||
|
;; and it does not work very well in our case, because that DBObject is short lived and produced
|
||||||
|
;; from the Clojure map we are passing in. Plus, this approach is very awkward with immutable data
|
||||||
|
;; structures being the default. MK.
|
||||||
|
(let [doc (merge {:_id (ObjectId.)} document)]
|
||||||
|
(insert db collection doc concern)
|
||||||
|
doc)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn ^WriteResult insert-batch
|
||||||
|
"Like monger.collection/insert-batch but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection ^List documents]
|
||||||
|
(.insert (.getCollection db (name collection))
|
||||||
|
^List (to-db-object documents)
|
||||||
|
monger.core/*mongodb-write-concern*))
|
||||||
|
([^DB db ^String collection ^List documents ^WriteConcern concern]
|
||||||
|
(.insert (.getCollection db (name collection))
|
||||||
|
^List (to-db-object documents)
|
||||||
|
concern)))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; monger.collection/find
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn ^DBCursor find
|
||||||
|
"Like monger.collection/find but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection ^Map ref]
|
||||||
|
(.find (.getCollection db (name collection))
|
||||||
|
(to-db-object ref)))
|
||||||
|
([^DB db ^String collection ^Map ref fields]
|
||||||
|
(.find (.getCollection db (name collection))
|
||||||
|
(to-db-object ref)
|
||||||
|
(as-field-selector fields))))
|
||||||
|
|
||||||
|
(defn find-maps
|
||||||
|
"Like monger.collection/find-maps but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection ^Map ref]
|
||||||
|
(with-open [dbc (find db collection ref)]
|
||||||
|
(map (fn [x] (from-db-object x true)) dbc)))
|
||||||
|
([^DB db ^String collection ^Map ref fields]
|
||||||
|
(with-open [dbc (find db collection ref fields)]
|
||||||
|
(map (fn [x] (from-db-object x true)) dbc))))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; monger.collection/find-one
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn ^DBObject find-one
|
||||||
|
"Like monger.collection/find-one but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection ^Map ref]
|
||||||
|
(.findOne (.getCollection db (name collection))
|
||||||
|
(to-db-object ref)))
|
||||||
|
([^DB db ^String collection ^Map ref fields]
|
||||||
|
(.findOne (.getCollection db (name collection))
|
||||||
|
(to-db-object ref)
|
||||||
|
^DBObject (as-field-selector fields))))
|
||||||
|
|
||||||
|
(defn ^IPersistentMap find-one-as-map
|
||||||
|
"Like monger.collection/find-one-as-map but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection ^Map ref]
|
||||||
|
(from-db-object ^DBObject (find-one db collection ref) true))
|
||||||
|
([^DB db ^String collection ^Map ref fields]
|
||||||
|
(from-db-object ^DBObject (find-one db collection ref fields) true))
|
||||||
|
([^DB db ^String collection ^Map ref fields keywordize]
|
||||||
|
(from-db-object ^DBObject (find-one db collection ref fields) keywordize)))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; monger.collection/find-by-id
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn ^DBObject find-by-id
|
||||||
|
"Like monger.collection/find-by-id but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection id]
|
||||||
|
(check-not-nil! id "id must not be nil")
|
||||||
|
(find-one db collection {:_id id}))
|
||||||
|
([^DB db ^String collection id fields]
|
||||||
|
(check-not-nil! id "id must not be nil")
|
||||||
|
(find-one db collection {:_id id} fields)))
|
||||||
|
|
||||||
|
(defn ^IPersistentMap find-map-by-id
|
||||||
|
"Like monger.collection/find-map-by-id but always takes a database as explicit argument"
|
||||||
|
([^DB db ^String collection id]
|
||||||
|
(check-not-nil! id "id must not be nil")
|
||||||
|
(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)))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; monger.collection/count
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn count
|
||||||
|
"Like monger.collection/count but always takes a database as explicit argument"
|
||||||
|
(^long [^DB db ^String collection]
|
||||||
|
(.count (.getCollection db (name collection)) (to-db-object {})))
|
||||||
|
(^long [^DB db ^String collection ^Map conditions]
|
||||||
|
(.count (.getCollection db (name collection)) (to-db-object conditions))))
|
||||||
|
|
@ -26,13 +26,19 @@
|
||||||
(defcleaner events) ;; collection name will be taken from the events-collection var
|
(defcleaner events) ;; collection name will be taken from the events-collection var
|
||||||
(defcleaner people \"accounts\") ;; collection name is given
|
(defcleaner people \"accounts\") ;; collection name is given
|
||||||
"
|
"
|
||||||
[entities & coll-name]
|
([entities]
|
||||||
(let [coll-arg (if coll-name
|
(let [coll-arg (symbol (str entities "-collection"))
|
||||||
(str (first coll-name))
|
fn-name (symbol (str "purge-" entities))]
|
||||||
(symbol (str entities "-collection")))
|
`(defn ~fn-name
|
||||||
fn-name (symbol (str "purge-" entities))]
|
[f#]
|
||||||
`(defn ~fn-name
|
(mc/remove ~coll-arg)
|
||||||
[f#]
|
(f#)
|
||||||
(mc/remove ~coll-arg)
|
(mc/remove ~coll-arg))))
|
||||||
(f#)
|
([entities coll-name]
|
||||||
(mc/remove ~coll-arg))))
|
(let [coll-arg (name coll-name)
|
||||||
|
fn-name (symbol (str "purge-" entities))]
|
||||||
|
`(defn ~fn-name
|
||||||
|
[f#]
|
||||||
|
(mc/remove ~coll-arg)
|
||||||
|
(f#)
|
||||||
|
(mc/remove ~coll-arg)))))
|
||||||
|
|
|
||||||
88
test/monger/test/multi/inserting_test.clj
Normal file
88
test/monger/test/multi/inserting_test.clj
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
(ns monger.test.multi.inserting-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 mc]
|
||||||
|
[monger.test.helper :as helper])
|
||||||
|
(:use clojure.test
|
||||||
|
monger.operators
|
||||||
|
monger.conversion
|
||||||
|
monger.test.fixtures))
|
||||||
|
|
||||||
|
(helper/connect!)
|
||||||
|
|
||||||
|
(defn drop-altdb
|
||||||
|
[f]
|
||||||
|
(mg/drop-db "altdb")
|
||||||
|
(f))
|
||||||
|
|
||||||
|
(use-fixtures :each drop-altdb)
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; insert
|
||||||
|
;;
|
||||||
|
|
||||||
|
(deftest insert-a-basic-document-without-id-and-with-default-write-concern
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "people"
|
||||||
|
doc {:name "Joe" :age 30}]
|
||||||
|
(is (monger.result/ok? (mc/insert db "people" doc)))
|
||||||
|
(is (= 1 (mc/count db collection)))))
|
||||||
|
|
||||||
|
(deftest insert-a-basic-document-with-explicitly-passed-database-without-id-and-with-default-write-concern
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "people"
|
||||||
|
doc {:name "Joe" :age 30}]
|
||||||
|
(dotimes [n 5]
|
||||||
|
(is (monger.result/ok? (mc/insert db "people" doc WriteConcern/SAFE))))
|
||||||
|
(is (= 5 (mc/count db collection)))))
|
||||||
|
|
||||||
|
(deftest insert-a-basic-document-without-id-and-with-explicit-write-concern
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "people"
|
||||||
|
doc {:name "Joe" :age 30}]
|
||||||
|
(is (monger.result/ok? (mc/insert db "people" doc WriteConcern/SAFE)))
|
||||||
|
(is (= 1 (mc/count db collection)))))
|
||||||
|
|
||||||
|
(deftest insert-a-basic-db-object-without-id-and-with-default-write-concern
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "people"
|
||||||
|
doc (to-db-object {:name "Joe" :age 30})]
|
||||||
|
(is (nil? (.get ^DBObject doc "_id")))
|
||||||
|
(mc/insert db "people" doc)
|
||||||
|
(is (not (nil? (monger.util/get-id doc))))))
|
||||||
|
|
||||||
|
(deftest insert-a-map-with-id-and-with-default-write-concern
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "people"
|
||||||
|
id (ObjectId.)
|
||||||
|
doc {:name "Joe" :age 30 "_id" id}
|
||||||
|
result (mc/insert db "people" doc)]
|
||||||
|
(is (= id (monger.util/get-id doc)))))
|
||||||
|
|
||||||
|
(deftest insert-a-document-with-clojure-ratio-in-it
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "widgets"
|
||||||
|
id (ObjectId.)
|
||||||
|
doc {:ratio 11/2 "_id" id}
|
||||||
|
result (mc/insert db "widgets" doc)]
|
||||||
|
(is (= 5.5 (:ratio (mc/find-map-by-id db collection id))))))
|
||||||
|
|
||||||
|
(deftest insert-a-document-with-clojure-keyword-in-it
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "widgets"
|
||||||
|
id (ObjectId.)
|
||||||
|
doc {:keyword :kwd "_id" id}
|
||||||
|
result (mc/insert db "widgets" doc)]
|
||||||
|
(is (= (name :kwd) (:keyword (mc/find-map-by-id db collection id))))))
|
||||||
|
|
||||||
|
(deftest insert-a-document-with-clojure-keyword-in-a-set-in-it
|
||||||
|
(let [db (mg/get-db "altdb")
|
||||||
|
collection "widgets"
|
||||||
|
id (ObjectId.)
|
||||||
|
doc {:keyword1 {:keyword2 #{:kw1 :kw2}} "_id" id}
|
||||||
|
result (mc/insert db "widgets" doc)]
|
||||||
|
(is (= (sort ["kw1" "kw2"])
|
||||||
|
(sort (get-in (mc/find-map-by-id db collection id) [:keyword1 :keyword2]))))))
|
||||||
Loading…
Reference in a new issue