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
|
||||
|
||||
### 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
|
||||
|
||||
`monger.cache/db-aware-monger-cache-factory` will return a MongoDB-backed `clojure.core.cache`
|
||||
|
|
|
|||
|
|
@ -9,36 +9,30 @@
|
|||
;; the terms of this license.
|
||||
;; 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
|
||||
queries, creating and dropping indexes, creating collections and more.
|
||||
(ns monger.collection
|
||||
"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/inserting.html
|
||||
* http://clojuremongodb.info/articles/querying.html
|
||||
* http://clojuremongodb.info/articles/updating.html
|
||||
* http://clojuremongodb.info/articles/deleting.html
|
||||
* http://clojuremongodb.info/articles/aggregation.html"}
|
||||
monger.collection
|
||||
* http://clojuremongodb.info/articles/getting_started.html
|
||||
* http://clojuremongodb.info/articles/inserting.html
|
||||
* http://clojuremongodb.info/articles/querying.html
|
||||
* http://clojuremongodb.info/articles/updating.html
|
||||
* http://clojuremongodb.info/articles/deleting.html
|
||||
* http://clojuremongodb.info/articles/aggregation.html"
|
||||
(:refer-clojure :exclude [find remove count drop distinct empty?])
|
||||
(: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 result])
|
||||
(:use [monger.conversion]))
|
||||
(:require monger.core
|
||||
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
|
||||
nil
|
||||
(to-db-object [input]
|
||||
input)
|
||||
nil)
|
||||
|
||||
String
|
||||
(to-db-object [^String input]
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@
|
|||
[]
|
||||
*mongodb-database*)
|
||||
|
||||
(defn drop-db
|
||||
"Drops a database"
|
||||
([^String db]
|
||||
(.dropDatabase *mongodb-connection* db))
|
||||
([^MongoClient conn ^String db]
|
||||
(.dropDatabase conn db)))
|
||||
|
||||
|
||||
(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:
|
||||
(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."
|
||||
([^Map 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 people \"accounts\") ;; collection name is given
|
||||
"
|
||||
[entities & coll-name]
|
||||
(let [coll-arg (if coll-name
|
||||
(str (first coll-name))
|
||||
(symbol (str entities "-collection")))
|
||||
fn-name (symbol (str "purge-" entities))]
|
||||
`(defn ~fn-name
|
||||
[f#]
|
||||
(mc/remove ~coll-arg)
|
||||
(f#)
|
||||
(mc/remove ~coll-arg))))
|
||||
([entities]
|
||||
(let [coll-arg (symbol (str entities "-collection"))
|
||||
fn-name (symbol (str "purge-" entities))]
|
||||
`(defn ~fn-name
|
||||
[f#]
|
||||
(mc/remove ~coll-arg)
|
||||
(f#)
|
||||
(mc/remove ~coll-arg))))
|
||||
([entities coll-name]
|
||||
(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