Merge branch 'master' of github.com:michaelklishin/monger
This commit is contained in:
commit
bdf0082372
11 changed files with 149 additions and 29 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -2,8 +2,7 @@ pom.xml
|
||||||
*jar
|
*jar
|
||||||
/lib/
|
/lib/
|
||||||
/classes/
|
/classes/
|
||||||
.lein-failures
|
.lein-*
|
||||||
.lein-deps-sum
|
|
||||||
TAGS
|
TAGS
|
||||||
checkouts/*
|
checkouts/*
|
||||||
doc/*
|
doc/*
|
||||||
|
|
|
||||||
12
CONTRIBUTING.md
Normal file
12
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
## Pre-requisites
|
||||||
|
|
||||||
|
The project uses [Leiningen 2](https://leiningen.org) and requires MongoDB `2.4+` to be running
|
||||||
|
locally. Make
|
||||||
|
sure you have those two installed and then run tests against all supported Clojure versions using
|
||||||
|
|
||||||
|
lein2 all test
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
Then create a branch and make your changes on it. Once you are done with your changes and all
|
||||||
|
tests pass, write a [good, detailed commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) submit a pull request on GitHub.
|
||||||
18
ChangeLog.md
18
ChangeLog.md
|
|
@ -1,3 +1,21 @@
|
||||||
|
## Changes between 1.5.0 and 1.6.0
|
||||||
|
|
||||||
|
### One More Cache Implementation
|
||||||
|
|
||||||
|
`monger.cache/db-aware-monger-cache-factory` will return a MongoDB-backed `clojure.core.cache`
|
||||||
|
implementation that can use any database:
|
||||||
|
|
||||||
|
``` clojure
|
||||||
|
(require '[monger.core :as mg])
|
||||||
|
(require '[monger.cache :as cache])
|
||||||
|
|
||||||
|
(let [db (mg/get-db "altcache")
|
||||||
|
coll "cache_entries"
|
||||||
|
c (cache/db-aware-monger-cache-factory db coll)]
|
||||||
|
(comment "This cache instance will use the altcache DB"))
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Changes between 1.4.0 and 1.5.0
|
## Changes between 1.4.0 and 1.5.0
|
||||||
|
|
||||||
### Full Text Search Support
|
### Full Text Search Support
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ definition to your `pom.xml`:
|
||||||
|
|
||||||
With Leiningen:
|
With Leiningen:
|
||||||
|
|
||||||
[com.novemberain/monger "1.5.0-rc1"]
|
[com.novemberain/monger "1.5.0"]
|
||||||
|
|
||||||
|
|
||||||
With Maven:
|
With Maven:
|
||||||
|
|
@ -60,7 +60,7 @@ With Maven:
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.novemberain</groupId>
|
<groupId>com.novemberain</groupId>
|
||||||
<artifactId>monger</artifactId>
|
<artifactId>monger</artifactId>
|
||||||
<version>1.5.0-rc1</version>
|
<version>1.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -132,6 +132,7 @@ on Github.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2011-2012 Michael S. Klishin
|
Copyright (C) 2011-2013 [Michael S. Klishin](http://twitter.com/michaelklishin)
|
||||||
|
|
||||||
Distributed under the [Eclipse Public License](http://www.eclipse.org/legal/epl-v10.html), the same as Clojure.
|
Double licensed under the [Eclipse Public License](http://www.eclipse.org/legal/epl-v10.html) (the same as Clojure) or
|
||||||
|
the [Apache Public License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
||||||
|
|
|
||||||
10
project.clj
10
project.clj
|
|
@ -1,4 +1,4 @@
|
||||||
(defproject com.novemberain/monger "1.5.0-rc2-SNAPSHOT"
|
(defproject com.novemberain/monger "1.6.0-beta2-SNAPSHOT"
|
||||||
:description "Monger is a Clojure MongoDB client for a more civilized age: friendly, flexible and with batteries included"
|
:description "Monger is a Clojure MongoDB client for a more civilized age: friendly, flexible and with batteries included"
|
||||||
:url "http://clojuremongodb.info"
|
:url "http://clojuremongodb.info"
|
||||||
:min-lein-version "2.0.0"
|
:min-lein-version "2.0.0"
|
||||||
|
|
@ -39,11 +39,11 @@
|
||||||
:1.6 {:dependencies [[org.clojure/clojure "1.6.0-master-SNAPSHOT"]]}
|
:1.6 {:dependencies [[org.clojure/clojure "1.6.0-master-SNAPSHOT"]]}
|
||||||
:master {:dependencies [[org.clojure/clojure "1.6.0-master-SNAPSHOT"]]}
|
:master {:dependencies [[org.clojure/clojure "1.6.0-master-SNAPSHOT"]]}
|
||||||
:dev {:resource-paths ["test/resources"]
|
:dev {:resource-paths ["test/resources"]
|
||||||
:dependencies [[clj-time "0.4.4" :exclusions [org.clojure/clojure]]
|
:dependencies [[clj-time "0.5.0" :exclusions [org.clojure/clojure]]
|
||||||
[cheshire "5.0.2" :exclusions [org.clojure/clojure]]
|
[cheshire "5.0.2" :exclusions [org.clojure/clojure]]
|
||||||
[org.clojure/tools.cli "0.2.1" :exclusions [org.clojure/clojure]]
|
[org.clojure/tools.cli "0.2.1" :exclusions [org.clojure/clojure]]
|
||||||
[org.clojure/core.cache "0.6.1" :exclusions [org.clojure/clojure]]
|
[org.clojure/core.cache "0.6.2" :exclusions [org.clojure/clojure]]
|
||||||
[ring/ring-core "1.1.2"]]
|
[ring/ring-core "1.1.8"]]
|
||||||
:plugins [[codox "0.6.4"]]
|
:plugins [[codox "0.6.4"]]
|
||||||
:codox {:sources ["src/clojure"]
|
:codox {:sources ["src/clojure"]
|
||||||
:output-dir "doc/api"
|
:output-dir "doc/api"
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
monger.ring.session-store]}}
|
monger.ring.session-store]}}
|
||||||
;; only clj-time/JodaTime available, used to test monger.joda-time w/o clojure.data.json
|
;; only clj-time/JodaTime available, used to test monger.joda-time w/o clojure.data.json
|
||||||
:dev2 {:resource-paths ["test/resources"]
|
:dev2 {:resource-paths ["test/resources"]
|
||||||
:dependencies [[clj-time "0.4.2" :exclusions [org.clojure/clojure]]]}}
|
:dependencies [[clj-time "0.5.0" :exclusions [org.clojure/clojure]]]}}
|
||||||
:aliases {"all" ["with-profile" "dev:dev,1.3:dev,1.4:dev,dj01x:dev,dj02x:dev,1.6"]}
|
:aliases {"all" ["with-profile" "dev:dev,1.3:dev,1.4:dev,dj01x:dev,dj02x:dev,1.6"]}
|
||||||
:repositories {"sonatype" {:url "http://oss.sonatype.org/content/repositories/releases"
|
:repositories {"sonatype" {:url "http://oss.sonatype.org/content/repositories/releases"
|
||||||
:snapshots false
|
:snapshots false
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
:author "Michael S. Klishin"}
|
:author "Michael S. Klishin"}
|
||||||
monger.cache
|
monger.cache
|
||||||
(:require [monger.collection :as mc]
|
(:require [monger.collection :as mc]
|
||||||
[clojure.core.cache :as cache])
|
[clojure.core.cache :as cache]
|
||||||
(:use monger.conversion)
|
[monger.conversion :as cnv])
|
||||||
(:import clojure.core.cache.CacheProtocol))
|
(:import clojure.core.cache.CacheProtocol
|
||||||
|
[com.mongodb DB DBObject WriteConcern]
|
||||||
|
java.util.Map))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Implementation
|
;; Implementation
|
||||||
|
|
@ -15,6 +17,24 @@
|
||||||
(def ^{:const true}
|
(def ^{:const true}
|
||||||
default-cache-collection "cache_entries")
|
default-cache-collection "cache_entries")
|
||||||
|
|
||||||
|
|
||||||
|
(defn- ^DBObject find-one
|
||||||
|
[^DB db ^String collection ^Map ref]
|
||||||
|
(.findOne (.getCollection db (name collection))
|
||||||
|
(cnv/to-db-object ref)))
|
||||||
|
|
||||||
|
(defn- find-by-id
|
||||||
|
"A version of monger.collection/find-by-id that does not require the
|
||||||
|
fields argument"
|
||||||
|
[^DB db ^String collection id]
|
||||||
|
(find-one db collection {:_id id}))
|
||||||
|
|
||||||
|
(defn- find-map-by-id
|
||||||
|
"A version of monger.collection/find-by-map-id that accepts database
|
||||||
|
as an argument"
|
||||||
|
[^DB db ^String collection id]
|
||||||
|
(cnv/from-db-object ^DBObject (find-one db collection {:_id id}) true))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; API
|
;; API
|
||||||
;;
|
;;
|
||||||
|
|
@ -24,11 +44,8 @@
|
||||||
(extend-protocol cache/CacheProtocol
|
(extend-protocol cache/CacheProtocol
|
||||||
BasicMongerCache
|
BasicMongerCache
|
||||||
(lookup [c k]
|
(lookup [c k]
|
||||||
(:value (mc/find-map-by-id (:collection c) k)))
|
(let [m (mc/find-map-by-id (:collection c) k)]
|
||||||
#_ (lookup [c k not-found]
|
(:value m)))
|
||||||
(if-let [doc (mc/find-map-by-id (:collection c) k)]
|
|
||||||
(:value doc)
|
|
||||||
not-found))
|
|
||||||
(has? [c k]
|
(has? [c k]
|
||||||
(not (nil? (mc/find-by-id (get c :collection) k))))
|
(not (nil? (mc/find-by-id (get c :collection) k))))
|
||||||
(hit [this k]
|
(hit [this k]
|
||||||
|
|
@ -52,3 +69,35 @@
|
||||||
(BasicMongerCache. collection))
|
(BasicMongerCache. collection))
|
||||||
([collection base]
|
([collection base]
|
||||||
(cache/seed (BasicMongerCache. collection) base)))
|
(cache/seed (BasicMongerCache. collection) base)))
|
||||||
|
|
||||||
|
|
||||||
|
(defrecord DatabaseAwareMongerCache [db collection])
|
||||||
|
|
||||||
|
(extend-protocol cache/CacheProtocol
|
||||||
|
DatabaseAwareMongerCache
|
||||||
|
(lookup [c k]
|
||||||
|
(let [m (find-map-by-id (:db c) (:collection c) k)]
|
||||||
|
(:value m)))
|
||||||
|
(has? [c k]
|
||||||
|
(not (nil? (find-by-id (:db c) (:collection c) k))))
|
||||||
|
(hit [this k]
|
||||||
|
this)
|
||||||
|
(miss [c k v]
|
||||||
|
(mc/insert (:db c) (:collection c) {:_id k :value v} WriteConcern/SAFE)
|
||||||
|
c)
|
||||||
|
(evict [c k]
|
||||||
|
(mc/remove-by-id (:db c) (:collection c) k)
|
||||||
|
c)
|
||||||
|
(seed [c m]
|
||||||
|
(mc/insert-batch (:db c) (:collection c) (map (fn [[k v]]
|
||||||
|
{:_id k :value v}) m) WriteConcern/SAFE)
|
||||||
|
c))
|
||||||
|
|
||||||
|
|
||||||
|
(defn db-aware-monger-cache-factory
|
||||||
|
([db]
|
||||||
|
(DatabaseAwareMongerCache. db default-cache-collection))
|
||||||
|
([db collection]
|
||||||
|
(DatabaseAwareMongerCache. db collection))
|
||||||
|
([db collection base]
|
||||||
|
(cache/seed (DatabaseAwareMongerCache. db collection) base)))
|
||||||
|
|
|
||||||
|
|
@ -555,9 +555,10 @@
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
|
|
||||||
;; create a regular index
|
;; create a regular index
|
||||||
(monger.collection/ensure-index \"documents\" {\"language\" 1})
|
;; clojure.core/array-map produces an ordered map
|
||||||
|
(monger.collection/ensure-index \"documents\" (array-map \"language\" 1))
|
||||||
;; create a unique index
|
;; create a unique index
|
||||||
(monger.collection/ensure-index \"pages\" {:url 1} {:unique true})
|
(monger.collection/ensure-index \"pages\" (array-map :url 1) {:unique true})
|
||||||
"
|
"
|
||||||
([^String collection ^Map keys]
|
([^String collection ^Map keys]
|
||||||
(.ensureIndex (.getCollection monger.core/*mongodb-database* (name collection)) (as-field-selector keys)))
|
(.ensureIndex (.getCollection monger.core/*mongodb-database* (name collection)) (as-field-selector keys)))
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
(defrecord ClojureReaderBasedMongoDBSessionStore [^String collection-name])
|
(defrecord ClojureReaderBasedMongoDBSessionStore [^String collection-name])
|
||||||
|
|
||||||
(defmethod print-dup java.util.Date
|
(defmethod print-dup java.util.Date
|
||||||
[^java.util.Date d ^java.io.OutputStream out]
|
[^java.util.Date d ^java.io.Writer out]
|
||||||
(.write out
|
(.write out
|
||||||
(str "#="
|
(str "#="
|
||||||
`(java.util.Date. ~(.getYear d)
|
`(java.util.Date. ~(.getYear d)
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
~(.getSeconds d)))))
|
~(.getSeconds d)))))
|
||||||
|
|
||||||
(defmethod print-dup org.bson.types.ObjectId
|
(defmethod print-dup org.bson.types.ObjectId
|
||||||
[oid out]
|
[oid ^java.io.Writer out]
|
||||||
(.write out
|
(.write out
|
||||||
(str "#="
|
(str "#="
|
||||||
`(org.bson.types.ObjectId. ~(str oid)))))
|
`(org.bson.types.ObjectId. ~(str oid)))))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
(ns monger.test.cache-test
|
(ns monger.test.cache-test
|
||||||
(:require [monger.test.helper :as helper]
|
(:require [monger.test.helper :as helper]
|
||||||
|
[monger.core :as mg]
|
||||||
[monger.collection :as mc])
|
[monger.collection :as mc])
|
||||||
(:use clojure.core.cache clojure.test monger.cache)
|
(:use clojure.core.cache clojure.test monger.cache)
|
||||||
(:import [clojure.core.cache BasicCache FIFOCache LRUCache TTLCache]
|
(:import [clojure.core.cache BasicCache FIFOCache LRUCache TTLCache]
|
||||||
|
|
@ -121,3 +122,42 @@
|
||||||
"Value" :skey
|
"Value" :skey
|
||||||
l :lkey
|
l :lkey
|
||||||
"keyword" "kkey"))))
|
"keyword" "kkey"))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest ^{:cache true}
|
||||||
|
test-has?-with-db-aware-monger-cache
|
||||||
|
(testing "that has? returns false for misses"
|
||||||
|
(let [db (mg/get-db "altcache")
|
||||||
|
coll "db_aware_monger_cache_entries"
|
||||||
|
c (db-aware-monger-cache-factory db coll)]
|
||||||
|
(is (not (has? c (str (UUID/randomUUID)))))
|
||||||
|
(is (not (has? c (str (UUID/randomUUID)))))))
|
||||||
|
(testing "that has? returns true for hits"
|
||||||
|
(let [db (mg/get-db "altcache")
|
||||||
|
coll "db_aware_monger_cache_entries"
|
||||||
|
c (db-aware-monger-cache-factory db coll {"a" 1 "b" "cache" "c" 3/4})]
|
||||||
|
(is (has? c "a"))
|
||||||
|
(is (has? c "b"))
|
||||||
|
(is (has? c "c"))
|
||||||
|
(is (not (has? c "d"))))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest ^{:cache true}
|
||||||
|
test-lookup-with-basic-moger-cache
|
||||||
|
(testing "that lookup returns nil for misses"
|
||||||
|
(let [db (mg/get-db "altcache")
|
||||||
|
coll "db_aware_monger_cache_entries"
|
||||||
|
c (db-aware-monger-cache-factory db coll)]
|
||||||
|
(are [v] (is (nil? (lookup c v)))
|
||||||
|
:missing-key
|
||||||
|
"missing-key"
|
||||||
|
(gensym "missing-key"))))
|
||||||
|
(testing "that lookup returns cached values for hits"
|
||||||
|
(let [l (Long/valueOf 10000)
|
||||||
|
db (mg/get-db "altcache")
|
||||||
|
coll "db_aware_monger_cache_entries"
|
||||||
|
c (db-aware-monger-cache-factory db coll {:skey "Value" :lkey l "kkey" :keyword})]
|
||||||
|
(are [v k] (is (= v (lookup c k)))
|
||||||
|
"Value" :skey
|
||||||
|
l :lkey
|
||||||
|
"keyword" "kkey"))))
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
(deftest ^{:edge-features true :search true} test-basic-full-text-search-query
|
(deftest ^{:edge-features true :search true} test-basic-full-text-search-query
|
||||||
(let [coll "docs"]
|
(let [coll "docs"]
|
||||||
(mc/ensure-index coll {:subject "text" :content "text"})
|
(mc/ensure-index coll (array-map :subject "text" :content "text"))
|
||||||
(mc/insert coll {:subject "hello there" :content "this should be searchable"})
|
(mc/insert coll {:subject "hello there" :content "this should be searchable"})
|
||||||
(mc/insert coll {:subject "untitled" :content "this is just noize"})
|
(mc/insert coll {:subject "untitled" :content "this is just noize"})
|
||||||
(let [res (ms/search coll "hello")
|
(let [res (ms/search coll "hello")
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@
|
||||||
(mc/create-index collection ["language"])
|
(mc/create-index collection ["language"])
|
||||||
(mc/drop-index collection "language_1")
|
(mc/drop-index collection "language_1")
|
||||||
(is (nil? (second (mc/indexes-on collection))))
|
(is (nil? (second (mc/indexes-on collection))))
|
||||||
(mc/ensure-index collection { "language" 1 } {:unique true})
|
(mc/ensure-index collection (array-map "language" 1) {:unique true})
|
||||||
(is (= "language_1"
|
(is (= "language_1"
|
||||||
(:name (second (mc/indexes-on collection)))))
|
(:name (second (mc/indexes-on collection)))))
|
||||||
(mc/ensure-index collection { "language" 1 })
|
(mc/ensure-index collection (array-map "language" 1))
|
||||||
(mc/ensure-index collection { "language" 1 } { :unique true })
|
(mc/ensure-index collection (array-map "language" 1) { :unique true })
|
||||||
(mc/drop-indexes collection)))
|
(mc/drop-indexes collection)))
|
||||||
|
|
||||||
(deftest ^{:indexing true :edge-features true :time-consuming true} test-ttl-collections
|
(deftest ^{:indexing true :edge-features true :time-consuming true} test-ttl-collections
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
ttl 30
|
ttl 30
|
||||||
sleep 120]
|
sleep 120]
|
||||||
(mc/remove coll)
|
(mc/remove coll)
|
||||||
(mc/ensure-index coll {:created-at 1} {:expireAfterSeconds ttl})
|
(mc/ensure-index coll (array-map :created-at 1) {:expireAfterSeconds ttl})
|
||||||
(dotimes [i 100]
|
(dotimes [i 100]
|
||||||
(mc/insert coll {:type "signup" :created-at (-> i secs ago) :i i}))
|
(mc/insert coll {:type "signup" :created-at (-> i secs ago) :i i}))
|
||||||
(dotimes [i 100]
|
(dotimes [i 100]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue