Compare commits

..

709 commits

Author SHA1 Message Date
Michael Klishin
78c1a37f2e
Merge pull request #235 from quelist/fix/update-before-scripts
Add MongoDB shell version detection to before scripts
2024-11-28 15:12:00 -05:00
quelist
705f4d6f47 Add MongoDB shell version detection to before scripts
Update before_script.sh and before_script_docker.sh to automatically detect and use the appropriate MongoDB shell command (mongo or mongosh) based on availability. This ensures compatibility with both:
- Legacy MongoDB versions using 'mongo' shell
- Modern MongoDB versions (5.0+) using 'mongosh'

The scripts now:
- Check for command availability
- Use the appropriate shell
- Exit with helpful error if no shell is found
2024-11-28 12:54:54 +05:30
Michael Klishin
182a3a6f0b
Merge pull request #234 from tuliolima/feat/supporting_newer_data_json_versions
Feat: supporting 3-ary clojure.data.json/write in newer versions
2024-04-07 21:30:25 -04:00
Tulio Abner de Lima
5852a5fe14 feat: supporting 3-arity clojure.data.json/write in newer versions
Starting at 2.0.0, clojure.data.json implements the additional
parameter `options` in `write` and other functions. The multi-arity
was used in protocol extension to support older and newer versions.
2024-04-04 10:09:20 -03:00
Michael Klishin
84170f7c51
Merge pull request #224 from chrisbroome/wrap-collection-names
Allow keywords as collection names in rename and aggreate
2023-01-19 08:37:42 -06:00
Michael Klishin
9f86984925
Merge pull request #226 from jzsampaio/jzsampaio-patch-1
:exclude random-uuid
2023-01-19 08:37:13 -06:00
Juarez Sampaio
92ea59ff3c
:exclude random-uuid
Should prevent this message when compiling:

> WARNING: random-uuid already refers to: #'clojure.core/random-uuid in namespace: monger.util, being replaced by: #'monger.util/random-uuid
2023-01-19 11:23:34 -03:00
Chris Broome
8deba612bb
Allow keywords as collection names in rename and aggreate 2022-12-01 21:59:06 -05:00
Michael Klishin
74a13a3489
Merge pull request #223 from crinklywrappr/from-db-object-perf
use transients to improve `from-db-object` performance
2022-10-27 09:51:35 +04:00
Daniel Fitzpatrick
14fd0d9189 improve from-db-object performance by leveraging transients 2022-10-26 14:43:41 -05:00
Michael Klishin
dfe29820e1
Merge pull request #222 from crinklywrappr/add-docker-support
add docker support
2022-10-25 20:52:08 +04:00
Daniel Fitzpatrick
999f6ddd9b add docker support 2022-10-25 11:43:05 -05:00
Michael Klishin
a70fd7936a
Merge pull request #220 from jacobemcken/feature/declare_operators
Avoid linter warning about unresolved operator
2022-09-09 11:55:36 +04:00
Jacob Emcken
62ef1d0727 Avoid linter warning about unresolved operator
Causing the message "Unresolved var"
2022-09-09 08:20:47 +02:00
Michael Klishin
54270ad887
Merge pull request #219 from jacobemcken/feature/remove-clj-kondo-cache
Avoid tracking clj-kondo cache in git history
2022-09-08 00:18:52 +04:00
Jacob Emcken
008d1ff1b0 Avoid tracking clojure-lsp cache in git history 2022-09-07 19:42:35 +02:00
Jacob Emcken
088b744991 Avoid tracking clj-kondo cache in git history 2022-09-07 18:23:51 +02:00
Michael Klishin
94cf59a53e
Merge pull request #216 from jacobemcken/cleanup/remove_warning
Prevent "random-uuid already refers to" warning
2022-09-03 14:10:18 +04:00
Jacob Emcken
69bb24b3d9 Prevent "random-uuid already refers to" warning
In Clojure 1.11 the function random-uuid was introduced in clojure.core
causing:

> WARNING: random-uuid already refers to: #'clojure.core/random-uuid in namespace: monger.util, being replaced by: #'monger.util/random-uuid
2022-09-03 08:23:13 +02:00
Michael Klishin
32407c92f1
Merge pull request #215 from punit-naik/master
`insert-batch` fn docfix
2022-06-26 22:26:46 +04:00
Punit Naik
d8ce4ae787
docfix 2022-06-23 18:43:43 +05:30
Michael Klishin
dac9f83a55
Back to dev version 2022-04-23 21:56:21 +04:00
Michael Klishin
9fb211e859
3.6.0 2022-04-23 21:30:18 +04:00
Michael Klishin
b5fd0a2738
More test massaging for MongoDB server 5.x 2022-04-23 21:29:45 +04:00
Michael Klishin
30cd472e23
Remove a test ns that needs reworking for MongoDB 5.x 2022-04-23 21:10:47 +04:00
Michael Klishin
ed613dee94
Bump dependencies 2022-04-23 21:10:21 +04:00
Michael Klishin
801f08b936
Change log updates 2022-04-23 21:04:29 +04:00
Michael Klishin
4d8747f9ed
Merge pull request #213 from okorz001/uuid-representation
Add uuid-representation option
2022-04-03 05:37:20 +04:00
Oscar Korz
ab878ab69c Add uuid-representation option 2022-04-02 15:44:44 -07:00
Michael Klishin
f30a3926e0
Merge pull request #206 from robhanlon22/bump-dependencies
Bump all dependency versions
2021-11-06 02:48:11 +03:00
Michael Klishin
e7c98d66e4
Merge pull request #203 from zackteo/zackteo-patch-1
Fix typo: weather to whether
2021-11-06 02:48:01 +03:00
Rob Hanlon
82ec258f6d
Add 1.9 profile to ensure back compat 2021-01-20 15:41:03 -08:00
Rob Hanlon
37c2d8433b
Bump all dependency versions 2021-01-20 15:38:20 -08:00
Zachary
0494128e15
Fix typo: weather to whether 2020-12-05 08:40:30 +08:00
Michael Klishin
9f3d192dff
Merge pull request #196 from mjrb/master
update operators for MongoDB 4.2
2020-08-10 00:46:26 +03:00
Michael Klishin
1fdd62d3df
Merge pull request #186 from geuscht-m/improve-distinct-tests
Add missing test case for distinct tests
2020-08-10 00:46:12 +03:00
Michael Klishin
c2cbdcaa38
Merge pull request #200 from bdrillard/mongo-options
Adds missing mongo options
2020-08-10 00:45:44 +03:00
Aleksander Eskilson
37aabbe860 testing over non-objects 2020-08-09 16:03:39 -05:00
Aleksander Eskilson
010a977aac adding mongo options 2020-08-09 16:01:20 -05:00
mjrb
b6bd6e55e2 update operators for MongoDB 4.2 2020-02-27 11:12:50 -05:00
Timo Geusch
ce6dcd27cb Added test case for distinct to exercise non-query distinct API
The existing test cases only covered the form (distinct ... :field
{query}). This chance adds a test for the non-query form also.
2019-04-24 14:06:16 -07:00
Timo Geusch
a67f6de06b Merge remote-tracking branch 'upstream/master' 2019-04-18 12:19:17 -07:00
Michael Klishin
d1b77ee3fd
Merge pull request #185 from juvenn/fix/openjdk
Try to use openjdk for travis build
2019-04-12 19:59:18 +04:00
Juvenn Woo
affeb65d00
Try to use openjdk for travis build 2019-04-10 12:13:59 +08:00
Michael Klishin
37816b77a1
Merge pull request #183 from jiacai2050/master
support set max-time on cursor
2019-02-28 17:44:33 +03:00
Jiacai Liu
ba29a45cc6
support set max-time on cursor 2019-02-28 16:48:06 +08:00
Michael Klishin
efc440a8f9
Change log updates 2018-12-10 15:41:15 +03:00
Michael Klishin
805383f1ec
Back to dev version 2018-12-10 15:28:35 +03:00
Michael Klishin
a3f6982a61
3.5.0 2018-12-10 15:23:54 +03:00
Michael Klishin
3a94b2a805
Move the sleep to .travis.yml
Since it's only really necessary in CI scenarios.
2018-12-10 15:21:42 +03:00
Michael Klishin
1e313f990c
Change log updates 2018-12-07 20:01:09 +03:00
Michael Klishin
d6f5ac743d
Compile for JDK 8 2018-12-07 19:55:34 +03:00
Michael Klishin
85c7b84d13
Merge branch 'chrisbroome-more-meaningful-uri-exception' 2018-12-07 19:52:12 +03:00
Michael Klishin
900592e302
Cosmetics, wording 2018-12-07 19:51:59 +03:00
Chris Broome
8102c42888
TravisCI: change dist to xenial
- Change distribution to `xenial`
- Remove custom mongodb 4.0 installation since xenial ships with 4.0
- Increase wait time from 5 to 15 seconds
2018-12-04 23:03:14 -05:00
Chris Broome
9d34fc0231
Throw IllegalArgumentException when database name not in uri 2018-12-04 21:20:25 -05:00
Chris Broome
aa08f4b58c
Add more descriptive error message when uri has no db name 2018-12-03 22:12:45 -05:00
Michael Klishin
4b591fc910
Back to dev version 2018-12-02 22:27:46 +03:00
Michael Klishin
79bd0aabca
3.5.0-rc1 2018-12-02 22:18:53 +03:00
Michael Klishin
6bf528ed5b
Bump version to 3.5.0
There are breaking changes that reflect breaking changes
in Monger's dependencies:

 * MongoDB server and Java client
 * core.cache
 * Ragtime

While not major, they can be breaking nonetheless so let's use a
greater minor version bump than usual to communicate the greater
than usual number of changes.
2018-12-02 21:45:44 +03:00
Michael Klishin
318e440d0d
(c) year 2018-12-02 21:45:26 +03:00
Michael Klishin
3757c6d915
Add a 3.6.x-compatible test seed script 2018-12-02 21:42:29 +03:00
Michael Klishin
a153eb8116
Travis: provision MongoDB 4.x 2018-12-02 21:38:56 +03:00
Michael Klishin
8879e552ef
Make before_script.sh compatible with MongoDB 4.0
Note that MongoDB 3.6 doesn't recognize the mechanisms field.
2018-12-02 21:38:17 +03:00
Michael Klishin
386f06da8c
Update dependencies, adapt to new core.cache and Ragtime APIs 2018-12-02 21:24:29 +03:00
Michael Klishin
ba00ba27a5
Encode this slash in URI 2018-12-02 21:24:05 +03:00
Michael Klishin
ad2ee531a3
$pushAll is gone, replaced by $push + $each
See https://docs.mongodb.com/v3.2/reference/operator/update/each/#up._S_each.
2018-12-02 21:23:20 +03:00
Michael Klishin
60c922c0a5
Merge pull request #175 from Freezystem/patch-1
Upgrade mongo drivers to 3.8.0 GA version
2018-12-01 03:49:54 +08:00
Michael Klishin
b2068fd8bb
Merge pull request #176 from seancorfield/patch-1
Add $position
2018-12-01 03:49:25 +08:00
Timo H. Geusch
595efb926f
Merge pull request #1 from michaelklishin/master
Merged upstream changes
2018-11-08 15:16:44 -05:00
Sean Corfield
f6e5ff75ce
Add $position
Modifier for $push
2018-08-31 17:48:25 -07:00
Nico
216674cd3d
Upgrade mongo drivers to 3.8.0 GA version
I'm trying to upgrade with latest mongoDB drivers for Java. 
In case these drivers are breaking the tests I'll try with former `3.7.1` or `3.6.4` drivers version.
2018-07-23 14:34:48 +02:00
Michael Klishin
f093322a09
Merge pull request #171 from vadyalex/feature/aggregate-keywordize-option
Add :keywordize option for aggregate that control if resulting map ke…
2018-07-23 02:37:34 +03:00
Michael Klishin
26efe88510
Merge pull request #174 from bowbahdoe/patch-1
Time passes.
2018-07-23 02:36:50 +03:00
Ethan McCue
da520112e7
Time passes. 2018-07-21 00:26:09 -04:00
Vladyslav Aleksakhin
7466db5c4d Add :keywordize option for aggregate that control if resulting map keys will be turned into keywords, default is true. 2018-05-02 11:07:31 +02:00
Michael Klishin
89e8538d91
Drop JDK 7 tests on Travis 2018-04-10 14:29:23 +03:00
Michael Klishin
a9e1f5d7d0
Merge pull request #167 from tirkarthi/patch-1
Add JDK 9 to Travis
2018-04-10 19:29:05 +08:00
Xtreak
dc61982ced
Add JDK 9 to Travis 2018-03-17 11:12:23 +05:30
Michael Klishin
002b91d5e6
Merge pull request #164 from amitvshah25/patch-1
Update operators.clj
2018-02-15 03:28:17 +03:00
Michael Klishin
3196b66442
Merge pull request #163 from xingzhefeng/master
support java Bigdecimal in mongodb 3.4 or later
2018-02-15 03:27:47 +03:00
amitvshah25
1a256a6033
Update operators.clj
Added count and dateToString operators.
2017-12-14 12:58:44 -05:00
冯忠孝
20b4d5d93b add travis-ci.org build image 2017-11-18 12:53:18 +08:00
冯忠孝
c35545a97a update sudo apt-key adv 2017-11-18 12:46:53 +08:00
冯忠孝
15831490d9 mongodb 3.4 repo url repair 2017-11-18 12:43:22 +08:00
冯忠孝
79387a694a This job is running on container-based infrastructure, which does not allow use of 'sudo', setuid, and setgid executables.
If you require sudo, add 'sudo: required' to your .travis.yml
2017-11-18 12:36:43 +08:00
冯忠孝
993bb038d9 ci test tip
No command 'lein2' found, did you mean:
test mongodb version up to 3.5
2017-11-18 12:14:55 +08:00
冯忠孝
5d31f9fc1a support java Bigdecimal in mongodb 3.4 or later 2017-11-18 11:31:45 +08:00
Michael Klishin
be43faf059 Update ChangeLog.md 2017-05-10 00:51:04 +03:00
Michael Klishin
bcaf0837b4 Merge pull request #157 from Linicks/patch-1
Update dependencies to support MongoDB 3.4.x
2017-05-10 00:48:58 +03:00
Nick
319872d5bc Update dependencies to support MongoDB 3.4.x
In order for Monger to work with MongoDB 3.4.x and higher, the Java driver must also be 3.4.x and higher.  Additionally, the 3.4.x driver series will generally work with Java version 6.x, it requires 7.x, and even 8.x for specific SSL functions that are needed by some "Platform As A Service" providers such as MongoDB Atlas.  Here are some relevant links that provide some additional details: 

- http://mongodb.github.io/mongo-java-driver/3.4/upgrading/
- https://docs.atlas.mongodb.com/driver-connection/#java-driver-example
- http://mongodb.github.io/mongo-java-driver/?_ga=2.85301265.905224850.1494354505-76319364.1488584191
2017-05-09 14:32:25 -07:00
Michael Klishin
6e333bb563 Merge pull request #154 from haines/fix-clojure-1.9-warning
Exclude clojure.core/any? to prevent warnings on Clojure 1.9
2017-02-10 19:04:48 +03:00
Andrew Haines
1ca1469126 Exclude clojure.core/any? to prevent warnings on Clojure 1.9 2017-02-10 15:21:02 +00:00
Michael Klishin
f3d8a7bb71 Merge pull request #153 from eunmin/add-affected-count
Add affected-count function for WriteResult
2017-01-11 13:09:46 +08:00
eunmin
99a113e220 Add affected-count function for WriteResult 2017-01-11 13:45:49 +09:00
Michael Klishin
c1acd78060 Merge pull request #150 from frooeyzanny/fix-pullAll-example
Fix $pullAll example
2016-11-20 19:44:11 +03:00
Michael Klishin
62dc2a9cd3 Merge pull request #149 from frooeyzanny/fix-subtract-operator
substract -> subtract
2016-11-20 19:43:54 +03:00
Michael Klishin
5b5425c402 Merge pull request #144 from caligin/master
fix: missing overload in :arglists, was causing eastwood to complain about correct calls
2016-11-20 19:43:27 +03:00
Michael Klishin
34671dcd5d Merge pull request #148 from jokimaki/close-stream-on-persist
Close GridFSInputFile input stream on persist
2016-11-20 19:43:03 +03:00
Juha Jokimaki
1170f342dd Delegate stream creation to GridFS 2016-11-20 18:03:11 +02:00
Evgeny Samsonov
27ed7bdfb7 Fix pullAll example 2016-11-02 18:14:31 +03:00
Evgeny Samsonov
517bb98129 substract -> subtract 2016-11-02 18:00:05 +03:00
Juha Jokimaki
b1cfb5490a Set GridFSInputFile closeStreamOnPersist flag 2016-10-31 08:52:14 +02:00
Michael Klishin
f499079bf7 Merge pull request #147 from jokimaki/operators
Add missing operators
2016-10-30 22:52:35 +03:00
Juha Jokimaki
0d7dc9357a Add $isolated operator 2016-10-30 18:15:51 +02:00
Juha Jokimaki
82c76dd66d Add $eq operator 2016-10-30 18:06:49 +02:00
Juha Jokimaki
2021c6d07f Fix $ne operator usage
The flaw was exposed when the test name was fixed.
2016-10-30 17:49:32 +02:00
Juha Jokimaki
3d4a38a10a Fix test name to match what is tested 2016-10-30 17:31:16 +02:00
Juha Jokimaki
8fd4946959 Add $where operator 2016-10-30 17:21:15 +02:00
Juha Jokimaki
08ce1e41b3 Add missing geospatial operators 2016-10-30 16:54:46 +02:00
Juha Jokimaki
a2bc59dcfa Test that every query operator is defined 2016-10-30 16:52:52 +02:00
Michael Klishin
d0fc0ed528 alpha13 is out 2016-10-10 00:17:01 +03:00
Fulvio Meden
57464ac592
fix: missing overload in :arglists, was causing eastwood to complain about correct calls 2016-10-04 14:24:19 +01:00
Michael Klishin
0f2a44179d
3.1.0 is out 2016-09-17 03:29:39 +03:00
Michael Klishin
7721c83ccf
Update change log 2016-09-17 03:29:21 +03:00
Michael Klishin
c374e7593b
Back to dev version 2016-09-17 03:28:45 +03:00
Michael Klishin
3e5f16d146
3.1.0 2016-09-17 03:27:10 +03:00
Michael Klishin
be95971e58
Bump MongoDB Java client to 3.3.0 2016-09-17 01:33:41 +03:00
Michael Klishin
2f19f62e3f Depend on Clojure 1.8, test against 1.9 previews 2016-08-20 09:35:09 +03:00
Michael Klishin
668e46d57f Merge pull request #141 from eunmin/add_currentDate_operator
Add currentDate operator
2016-08-19 08:41:29 +03:00
eunmin
df09c4085d Add operator 2016-08-19 14:19:50 +09:00
Michael Klishin
5033018119 Merge pull request #140 from eunmin/master
Add missing MongoClientOptions
2016-07-07 15:32:20 +03:00
eunmin
ccffffc912 Add missing MongoClientOptions 2016-07-07 21:17:59 +09:00
Michael Klishin
9be707ea06 Merge pull request #135 from kronos/master
Fix keywordize param for find-map-by-id
2016-04-27 11:06:36 -05:00
Samsonov Ivan
2b4c0f8168 Fix keywordize param for find-map-by-id 2016-04-26 19:03:44 +03:00
Michael Klishin
f64d085b0f Merge pull request #133 from divs1210/master
Fix reflection warnings.
2016-04-07 14:55:33 +03:00
Divyansh Prakash
5916642b2b Fix reflection warnings. 2016-04-07 16:52:02 +05:30
Michael Klishin
07b63150d1 Test against Clojure 1.8.0 2016-03-31 02:55:15 +03:00
Michael Klishin
e842068f3e Merge pull request #132 from tuhlmann/master
Fixing call to find-map-by-id, threw a ClassCastException
2016-03-27 19:34:50 +03:00
Torsten Uhlmann
9d51f32fa1 Fixing call to find-map-by-id, threw a ClassCastException
Fixes #131
2016-03-27 13:07:38 +02:00
Michael Klishin
765b9d1acf Update change log 2016-01-16 14:31:27 +03:00
Michael Klishin
c54f70350e Merge branch 'boechat107-typehint' 2016-01-16 14:28:52 +03:00
Michael Klishin
c7a87ac776 Merge branch 'typehint' of https://github.com/boechat107/monger into boechat107-typehint 2016-01-16 14:25:50 +03:00
Andre Ambrosio Boechat
bdecd98b40 with-collection macro: type hints improvement
From all the resources I found about type hinting in macros,
it doesn't work like it does for normal functions.

I got reflection warnings for a code like this:

```clj
(let [conn (mg/connect)
      db (delay (mg/get-db conn "monger-test"))]
  (with-collection @db "something"
    (find {})))
```

The type hint for `db` didn't work. Actually the type hint that works
comes from the function `core/get-db` and we see this when we remove
`delay` from the code above. As we could expect, the function `deref`
doesn't propagate the type hint.

I did similar tests with the collection name and no reflection warning
was raised for any case. In addition, it looked weird for me to have
a type hint like `^String` and then a checking like `string?` later.

Some references:

* http://stackoverflow.com/questions/11919602/generating-clojure-code-with-type-hints
* Clojure High Performance Programming, page 44.
2016-01-15 15:47:47 +01:00
Michael Klishin
189d347f50 Merge branch '3.0.x-stable' 2016-01-10 23:46:23 +03:00
Michael Klishin
114630f769 Back to dev version 2016-01-10 23:44:39 +03:00
Michael Klishin
6c25763748 3.0.2 2016-01-10 23:44:39 +03:00
Michael Klishin
fdb354b2db Update change log 2016-01-10 23:44:39 +03:00
Michael Klishin
45cb68115b Upgrade Java client to 3.2.0 2016-01-10 23:44:39 +03:00
Stijn Opheide
dd890231ee Fix cursor hinting
The .hint method should be applied on the cursor object instead
of the DBObject contained in the hint field.
2016-01-10 23:44:39 +03:00
Michael Klishin
1764b898bd Merge pull request #126 from stijnopheide/fix-cursor-hint
Fix cursor hinting
2016-01-06 14:33:38 +03:00
Stijn Opheide
b0df70f279 Fix cursor hinting
The .hint method should be applied on the cursor object instead
of the DBObject contained in the hint field.
2016-01-06 12:00:08 +01:00
Michael Klishin
85560e17f8 Update (c) year 2016-01-02 04:43:29 +03:00
Michael Klishin
57fb96a1b7 Upgrade to Codox 0.9.0 2015-12-20 02:11:15 +03:00
Michael Klishin
47d20761c5 Merge pull request #121 from Deraen/master
Add changelog entry for from-db-object perf improvement
2015-10-09 14:52:47 +03:00
Juho Teperi
50a8963ba2 Add changelog entry for from-db-object perf improvement 2015-10-09 12:56:43 +03:00
Michael Klishin
2856631638 Merge pull request #120 from Deraen/improve-from-db-object-perf
Improve from db object perf
2015-10-09 00:58:42 +03:00
Juho Teperi
1299e5e5ff Remove from-db-object implementation for Map
It should be enough that from-db-object is implemented for DBObject
2015-10-09 00:49:28 +03:00
Juho Teperi
cf3d8f2ad3 Fix test cases cases trying to compare db-objects and maps 2015-10-09 00:48:57 +03:00
Juho Teperi
15edf63ffd Fix test cases with bad = forms 2015-10-09 00:24:29 +03:00
Juho Teperi
c26ae0835d Optimize from-db-object performance for DBObjects
Creating temporary sequence from DBObject is quite slow. Using
.keySet for reduce collection and calling .get inside reduce is
considerably faster. The common code between Map and DBObject
implementations can't be shared as reflection would completely kill the
performance and function can't be type hinted as DBObject doesn't
implement Map interface.

Added a simple test case for the from-db-object performance. I'm seeing
performance increase of 20% on this (170ms -> 140ms).
2015-10-08 22:59:47 +03:00
Juho Teperi
fe73144075 Fix map comparisons and rename test case
Two tests had the same name so only the latter was ran
2015-10-08 22:42:06 +03:00
Michael Klishin
2dc5e92b0c Merge pull request #119 from tommireinikainen/update-contributing-md
Minor updates to CONTRIBUTING.md
2015-09-25 03:24:39 -07:00
Tommi Reinikainen
286493463b add note to run before_script before tests, remove MongoDB version, fix Leiningen link 2015-09-25 10:03:28 +03:00
Michael Klishin
aec51c03f4 MongoDB Java driver 3.0.4 2015-09-25 01:50:27 +03:00
Michael Klishin
7195f77945 Install MongoDB 3.0 before running tests 2015-09-25 01:49:04 +03:00
Michael Klishin
b59ccb4087 Make this script executable 2015-09-25 01:48:58 +03:00
Michael Klishin
9178df179d MongoDB installation script 2015-09-25 01:48:52 +03:00
Michael Klishin
8cefa7fc9e Test 3.0.x, 2.1.x is no longer maintained 2015-09-25 01:48:46 +03:00
Michael Klishin
45599a4f51 Print MongoDB version on Travis 2015-09-25 01:48:35 +03:00
Michael Klishin
4e9f041ce9 Install MongoDB 3.0 before running tests 2015-09-25 01:45:38 +03:00
Michael Klishin
f24ee77730 Make this script executable 2015-09-25 01:44:48 +03:00
Michael Klishin
9928652b79 MongoDB installation script 2015-09-25 01:44:24 +03:00
Michael Klishin
56d16a4cee Test 3.0.x, 2.1.x is no longer maintained 2015-09-25 01:31:23 +03:00
Michael Klishin
a500638891 Print MongoDB version on Travis 2015-09-25 01:31:11 +03:00
Michael Klishin
8bce5ae8ed 3.0.1 is out 2015-09-25 01:28:30 +03:00
Michael Klishin
2dc924faf4 Update change log 2015-09-25 01:28:21 +03:00
Michael Klishin
1f395c4e41 Back to dev version 2015-09-25 01:27:38 +03:00
Michael Klishin
bfac6bbe3a 3.0.1 2015-09-25 01:27:01 +03:00
Michael Klishin
def4ce3e6b Update change log 2015-09-25 01:26:54 +03:00
Michael Klishin
504a358162 MongoDB Java driver 3.0.4 2015-09-25 01:25:48 +03:00
Michael Klishin
5898cfb3bc Back to dev version 2015-09-25 01:25:17 +03:00
Artem Chistyakov
cf86245526 Don’t forget to pass credentials to MongoClient
It looks like provided credentials are ignored unless `server-address` is a collection.
2015-09-25 01:18:13 +03:00
Artem Chistyakov
8316e7798e Don’t forget to pass credentials to MongoClient
It looks like provided credentials are ignored unless `server-address` is a collection.
2015-09-18 16:07:01 -04:00
Michael Klishin
5f53732719 Merge pull request #114 from stereoderevo/Keywordise_find_maps
Keywordise find maps
2015-08-25 19:01:15 +03:00
Andrei Biasprozvanny
ee0c3dbede Updated Readme to include before-script.sh when running the tests 2015-08-25 16:50:35 +01:00
Andrei Biasprozvanny
ebc01b3f54 Find-maps now supports keywordize option 2015-08-25 16:48:17 +01:00
Andrei Biasprozvanny
f1fff71577 Add IntelliJ files to .gitignore 2015-08-25 16:16:29 +01:00
Michael Klishin
e0c632f0d3 Test against Clojure 1.8.0-alpha4 2015-08-09 15:44:17 +03:00
Michael Klishin
f3cff7a52a Test against Clojure 1.8.0-alpha3 2015-08-01 02:51:15 +03:00
Michael Klishin
fc4a34b87f Update change log 2015-08-01 02:47:12 +03:00
Michael Klishin
76cd30d79c Java driver 3.0.03 2015-08-01 02:46:15 +03:00
Michael Klishin
6c1489e1ef Merge pull request #111 from ebaxt/master
Monger calls removed com.mongodb.MongoClientOptions$Builder methods
2015-07-23 00:53:58 +03:00
Erik Bakstad
d9b103c350 Removed call to removed MongoClientOptions.Builder methods 2015-07-22 21:38:41 +02:00
Erik Bakstad
43994ff19a Failing test that calls removed MongoClientOptions.Builder methods 2015-07-22 21:36:42 +02:00
Michael Klishin
95d0145a0b Test against Clojure 1.8.0-alpha2 2015-07-18 03:39:39 +03:00
Michael Klishin
7e111a332e 3.0.0 2015-07-16 23:38:08 +03:00
Michael Klishin
800d02839c 3.0.0 is out 2015-07-16 23:38:08 +03:00
Michael Klishin
19613b6e01 Bump Cheshire to 5.5.0 2015-07-16 23:38:08 +03:00
Michael Klishin
ec5590fd56 Back to dev version 2015-07-16 23:38:08 +03:00
Michael Klishin
c1597b1c9a Make this test order independent 2015-07-16 23:38:08 +03:00
Michael Klishin
478efa092d Bump clojure.data.json to 0.2.6 2015-07-16 23:38:08 +03:00
Michael Klishin
ac90956f92 Don't test against clojure.data.json 0.1.x 2015-07-16 23:38:08 +03:00
Michael Klishin
1da1dab013 Test against 1.6 via a profile, drop 1.5 support 2015-07-16 23:38:07 +03:00
Michael Klishin
80cadd54c4 Depend on Clojure 1.7 2015-07-16 23:37:34 +03:00
Michael Klishin
b4ea572293 Clojure master is now 1.8.0-master-SNAPSHOT 2015-07-12 01:16:03 +03:00
Michael Klishin
ae2ac84921 Test against Clojure 1.7.0 GA 2015-07-12 01:07:23 +03:00
Michael Klishin
0891a9ded7 Update change log 2015-06-27 23:24:26 +03:00
Michael Klishin
51baa3e154 Adhere to the existing code style 2015-06-27 23:16:11 +03:00
Michael Klishin
1717bdac9e rc2 is out 2015-06-27 23:10:46 +03:00
Michael Klishin
7f74d16a36 Test against Clojure 1.7.0-RC2 2015-06-27 23:10:24 +03:00
Michael Klishin
2cd8c0c6a0 Back to dev version 2015-06-27 23:08:46 +03:00
Michael Klishin
ceed6f85c5 3.0.0-rc2 2015-06-27 23:06:48 +03:00
Michael Klishin
4ff7d05aa4 monger.credentials/for => monger.credentials/create
To make sure we don't shadow clojure.core/for when monger.credentials
is required with :refer :all.
2015-06-27 22:39:01 +03:00
Michael Klishin
b762c1875f Bump Java driver to 3.0.2 2015-06-27 22:13:23 +03:00
Bartek Marcinowski
15f50408a9 Merge branch 'add_options_to_aggregate'
Merge implementation of aggregation framework options and explanation of
aggregation query plan.

Conflicts:
	src/clojure/monger/collection.clj
2015-06-24 16:05:47 +01:00
Bartek Marcinowski
f0946acd75 Enable query plan explanation for the aggregation framework
Add the explain-aggregate function, which returns a map containing
information about the given aggregation query.
2015-06-24 15:51:24 +01:00
Bartek Marcinowski
136dea00b2 Add allow-disk-use and cursor options to aggregate
Reimplement aggregate on top of the Java driver's DBCollection#aggregate
in order to return a cursor for the results. This allows users to
overcome the 16MB result size limit and specify the cursor batch size.
The allowDiskUse can also be passed to Mongo, through the allow-disk-use
key. The maxTime option enables setting a limit (in milliseconds) on the
execution time of the query, through the max-time key.
2015-06-24 15:47:46 +01:00
Michael Klishin
3a4de68dd4 Merge pull request #105 from karstendick/fix/ensure-index-name
Fix 5-arity ensure-index by renaming `name` argument
2015-06-24 07:41:01 +03:00
Joshua Karstendick
9c0f385ab2 Fixes a bug with the 5-arity ensure-index function. The argument
named `name` shadowed clojure.core/name, so trying to call `name`
as a function on line 426 throws an exception. Fixes the bug by
renaming the argument to `index-name`.
2015-06-23 17:21:12 -04:00
Joshua Karstendick
d337cd1546 added failing unit test 2015-06-23 17:21:05 -04:00
Michael Klishin
94029c7f6c Support aggregation options, closes #102 2015-06-23 22:01:06 +03:00
Michael Klishin
aeab2851c1 Merge pull request #104 from kronos/master
Connect via uri in core/connect if it is passed
2015-06-16 00:54:26 +03:00
Ivan Samsonov
126c9f8503 Connect via uri in core/connect if it is passed
core/connect ignores :uri key and tries to connect 127.0.0.1:27017 instead.
Patch fix this behaviour by checking uri key existance and trying to connect
by uri if it's provided.
2015-06-15 02:45:11 +03:00
Michael Klishin
6e41cb94d8 Link to MongoDB Java driver 3.0 2015-06-15 01:32:49 +03:00
Michael Klishin
3edc8049db README updates 2015-06-14 02:09:06 +03:00
Michael Klishin
e76dc21182 3.0.0-rc1 is out 2015-06-14 02:08:11 +03:00
Michael Klishin
d80a2766ee Back to dev version 2015-06-13 22:17:06 +03:00
Michael Klishin
2eb6f80ae8 3.0.0-rc1 2015-06-13 19:47:52 +03:00
Michael Klishin
eb168b6830 2.1.0 is out 2015-06-07 15:12:23 +03:00
Michael Klishin
4701a7b5ab Merge pull request #101 from michaelklishin/issue-99
Update license headers
2015-06-06 19:15:50 +03:00
Michael Klishin
a2b1ddb054 Update license headers 2015-06-06 19:15:01 +03:00
Michael Klishin
4e0a0036e6 Begin preparing change log for 3.0 2015-05-20 01:13:03 -07:00
Michael Klishin
5651c2ee97 This is no longer necessary
Since we no longer support Clojure 1.3.
2015-05-18 06:33:16 -07:00
Michael Klishin
3660992148 Update ChangeLog.md 2015-05-17 13:28:22 -07:00
Tom McMillen
602b6e3ce9 Add JSON serialization of BSONTimestamp 2015-05-17 13:27:40 -07:00
Michael Klishin
3e71b6ffc7 Commit monger.credentials 2015-05-17 18:53:14 +03:00
Michael Klishin
4efdaa28c9 Ignore nREPL files 2015-05-17 18:53:08 +03:00
Michael Klishin
8b2fd956e4 Rework authentication for the 3.0 client and multiple server versions
When authentication failures, MongoDB Java client throws a timeout
exception whose cause is a failed command exception which carries
a reason. Still not great at authentication failure notification.
2015-05-17 18:51:44 +03:00
Michael Klishin
6ca5b9d4ba monger.search is gone
Full text search in 3.0 is supported via regular queries
with the $text operator.
2015-05-16 15:38:41 +03:00
Michael Klishin
a8d42a62f5 Adapt this test for 3.0 2015-05-11 01:42:01 +03:00
Michael Klishin
a107f1f8b7 Adapt for Java driver 3.0 2015-05-11 01:36:24 +03:00
Michael Klishin
3c63209ab1 Make sure hint isn't set to nil
MongoDB 3.0 is not as lenient about it.
2015-05-11 01:20:56 +03:00
Michael Klishin
05dd57731a Adapt to 3.0 2015-05-11 01:20:18 +03:00
Michael Klishin
26be7bb1b9 Make command-test pass 2015-05-11 01:19:47 +03:00
Michael Klishin
2be051289f Use GA version of the Java driver 2015-05-11 01:19:31 +03:00
Michael Klishin
096ba46bcd Ignore todo.org 2015-05-11 00:16:18 +03:00
Michael Klishin
07a9c5ee16 Silence MongoDB Java driver logger 2015-05-11 00:15:56 +03:00
Michael Klishin
49cb195e5a Adapt before_script.sh to createUser in 3.0 GA 2015-05-11 00:04:31 +03:00
Michael Klishin
7c31e98cf3 addUser is superceded by createUser 2015-02-22 19:28:11 +03:00
Michael Klishin
0b72761b44 Adapt monger.{core,collection} and tests to recent changes
Down to 50 failures and 11 errors in `lein test`.
2015-02-22 19:26:27 +03:00
Michael Klishin
8511d3714d Reduce monger.result to two functions: acknowledged? and
`updated-existing?`

`ok?` and other variations are now all superceded by `acknowledged?`,
`WriteConcern/ACKNOWLEDGED` is the recommended way of ensuring safe
writes.
2015-02-22 19:24:51 +03:00
Michael Klishin
d9e6be671a Monger's DBRef cannot work with com.mongodb.DBRef without fundamental re-thinking
com.mongodb.DBRef#fetch was removed.
2015-02-22 19:24:10 +03:00
Michael Klishin
2128f2cd6c getLastError is gone in the 3.0 driver 2015-02-22 18:52:31 +03:00
Michael Klishin
bb626c5320 Don't run CI against this WIP branch 2015-02-21 17:47:23 +03:00
Michael Klishin
25c1c56fc9 This DFRef ctor was removed 2015-02-21 12:20:06 +03:00
Michael Klishin
e7755b3fc5 Use Java driver 3.0.0-beta2 2015-02-21 12:19:49 +03:00
Michael Klishin
cd4326ca69 Next release will be 3.0 2015-02-21 12:17:49 +03:00
Michael Klishin
9cb54167c4 2.1.0 2015-02-21 12:16:08 +03:00
Michael Klishin
732bdb40e0 Update change log 2015-02-21 12:10:44 +03:00
Michael Klishin
2d58b02b13 Upgrade to MongoDB 2.13.0 2015-02-21 12:10:01 +03:00
Michael Klishin
7bf5956565 Test against Clojure 1.7.0-alpha5 2015-01-10 18:35:27 +03:00
Michael Klishin
d0d922e78c Bump Leiningen requirement to 2.5.1 2015-01-10 18:25:32 +03:00
Michael Klishin
6b6876186b More README updates, sync with upstream 2015-01-02 13:58:13 +03:00
Michael Klishin
1a30ef4247 (c) year 2015-01-02 13:56:57 +03:00
Michael Klishin
916d83b705 Remove Bitdeli badge 2015-01-02 13:56:40 +03:00
Michael Klishin
6fa11f9b76 Wording 2015-01-02 13:56:31 +03:00
αλεx π
1215f0335a Merge pull request #95 from podviaznikov/patch-1
Use SVG badges instead of PNG
2014-12-17 11:18:52 +01:00
Anton Podviaznikov
80773ad0af Use SVG badges instead of PNG
SVG badges look much better on retina
2014-12-16 18:28:36 -08:00
Michael Klishin
3389e84bb2 lein2 => lein 2014-12-16 00:02:33 +03:00
Michael Klishin
e6dfd9dd5e Add jarkeeper 2014-12-15 23:54:22 +03:00
Michael Klishin
d63982491b 2.0.1 is out 2014-12-15 23:51:54 +03:00
Michael Klishin
fb00629345 Depend on Validateur 2.4.2 2014-12-15 22:10:24 +03:00
Michael Klishin
cd7e7db809 Ignore pom.xml.asc files 2014-12-07 16:56:33 +03:00
Michael Klishin
e3189c33c7 Update change log 2014-12-07 16:56:18 +03:00
Michael Klishin
0495d74a34 Java driver 2.12.4 2014-12-07 16:55:39 +03:00
Michael Klishin
a1f3566632 Correct docstring example 2014-11-19 15:16:52 +00:00
Michael Klishin
78ea72a33b Add license URL to project.clj 2014-11-16 05:11:38 +03:00
Michael Klishin
5c39babf69 Attempt to fix the build 2014-11-15 20:11:08 +03:00
Michael Klishin
361d293a93 Bump clj-time dependency 2014-11-15 20:04:02 +03:00
Michael Klishin
049fa620c8 Test against 1.7, drop 1.4 2014-11-15 20:03:18 +03:00
Michael Klishin
194f0028a4 Merge pull request #90 from Skinney/issue-77
Fix for Issue 77
2014-10-21 09:34:43 +04:00
Robin Heggelund Hansen
1c62587165 Fixes #77: Add update-by-ids function to mongo.collection 2014-10-21 06:06:06 +02:00
Robin Heggelund Hansen
696a5ad8e3 Added tests for 'update' functions 2014-10-21 05:59:28 +02:00
Stijn Opheide
b0accb8447 Exclude clojure.core/update from monger.collection.
clojure.core/update was introduced in clojure 1.7. To avoid clashing
with monger.collection/update it has to be excluded in the latter
namespace.
2014-10-17 13:04:37 +04:00
Michael Klishin
2c05d4c9d5 Remove the deprecation note since it is only confusing these days 2014-10-11 03:40:40 +04:00
Michael Klishin
d8e70a5ee8 Bump Leiningen requirement to 2.5.0 2014-09-18 08:04:23 +04:00
Michael Klishin
30fececda4 Support 1.1.0 2014-09-14 02:13:32 +04:00
Michael Klishin
1f0f97869f Test against ragtime 0.3.7 2014-09-14 02:12:49 +04:00
Michael Klishin
ea158554fc Merge pull request #86 from Skinney/object-id-str
Allow object-id to convert string to object-id
2014-08-07 05:57:04 +04:00
Robin Heggelund Hansen
00dad8d0fb Allow object-id to convert string to object-id 2014-08-07 01:23:30 +02:00
Michael Klishin
0312ecd2f6 Bump Leiningen requirement to 2.4.3 (uses HTTPS for Maven Central) 2014-08-06 05:39:40 +04:00
Michael Klishin
ef539f48c8 Update change log 2014-07-18 18:01:43 +04:00
Michael Klishin
1ac5086b17 Merge pull request #84 from jokimaki/each
Support for $each modifier
2014-07-18 17:08:34 +04:00
Juha Jokimäki
2c019e5e91 Support for $each modifier 2014-07-18 14:47:37 +03:00
Michael Klishin
a8a9ab16b6 Codox 0.8.10 2014-06-30 22:32:21 +04:00
Michael Klishin
8addd14c6d Depend on Support 1.0 2014-06-25 22:17:01 +04:00
Michael Klishin
bf5ded8939 Bump Leiningen requirement to 2.4 2014-06-25 21:36:26 +04:00
Michael Klishin
c0fb8c517b Cosmetics 2014-06-22 14:01:32 +04:00
Michael Klishin
2234f0fb22 Wording 2014-06-22 14:01:10 +04:00
Michael Klishin
af6f300720 2.0.0 is out 2014-06-22 13:51:54 +04:00
Michael Klishin
bcea07dff4 Back to dev version 2014-06-15 17:43:01 +04:00
Michael Klishin
b0d8996576 2.0.0 2014-06-15 17:41:57 +04:00
Michael Klishin
e73372bc1a Test against clj-time 0.7.0 2014-06-15 17:41:44 +04:00
Michael Klishin
cac5ee4695 Test against Ring 1.3 2014-06-15 17:41:32 +04:00
Michael Klishin
f846cd0a51 Make mongo-options take a map instead of pseudo-kwards, extract mongo-options-builder 2014-06-15 17:39:32 +04:00
Michael Klishin
59427e29bb Cosmetics 2014-06-15 17:31:35 +04:00
Michael Klishin
e8b5ba5dd6 Cosmetics 2014-06-15 17:29:31 +04:00
Michael Klishin
417763782e Bump Leiningen requirement to 2.3 2014-06-07 00:08:47 +04:00
Michael Klishin
21174924c3 Codox 0.8.9 2014-06-05 21:54:22 +04:00
Michael Klishin
b1049021c0 Codox 0.8.8 2014-06-03 20:52:33 +04:00
Michael Klishin
37e94ebcd5 Drop JDK 6 2014-06-01 17:18:08 +04:00
Michael Klishin
081a7fc3d6 Enable JDK 8 on travis 2014-06-01 17:13:38 +04:00
Michael Klishin
96f7e67489 Codox 0.8.5 2014-06-01 15:53:21 +04:00
Michael Klishin
40bc1861a7 Cosmetics 2014-05-29 01:27:58 +04:00
Michael Klishin
57dbfd0e56 Sync with upstream 2014-05-29 00:57:33 +04:00
Michael Klishin
cb6210d573 Cosmetics 2014-05-29 00:55:47 +04:00
Michael Klishin
53ce5808c4 Cosmetics 2014-05-29 00:40:27 +04:00
Michael Klishin
3f3a6420e5 Merge pull request #80 from life4go/patch-1
fix doc error for update
2014-05-18 08:13:29 +04:00
Deamon Wang
6330cee24a fix doc error for update 2014-05-18 12:10:05 +08:00
Michael Klishin
96f05c7c01 Update change log 2014-05-14 07:23:42 +04:00
Michael Klishin
a259bd3e00 2.0.0-rc1 is out 2014-05-14 07:19:20 +04:00
Michael Klishin
2e1ad71d08 Back to dev version 2014-05-14 07:18:43 +04:00
Michael Klishin
646f4e1bd1 2.0.0-rc1 2014-05-14 07:16:40 +04:00
Michael Klishin
6206308fa8 WriteConcern/SAFE was renamed (and is the default, so not very demonstrative) 2014-05-13 05:06:23 +04:00
Michael Klishin
da2effbfc9 Merge pull request #78 from michaelklishin/explicit-db-argument
Finishes #76
2014-05-12 08:20:29 +04:00
Michael Klishin
31ee101d5d Begin updating change log for 2.0 2014-05-11 13:51:48 -04:00
Michael Klishin
ad25fba0f0 Exclusion for Validateur, too 2014-05-11 13:43:18 -04:00
Michael Klishin
b86ecb5487 More exclusions 2014-05-11 13:42:15 -04:00
Michael Klishin
5215574377 Use 0.6 for now 2014-05-11 13:40:43 -04:00
Michael Klishin
25f6dcf88d Bump clj-time 2014-05-11 13:40:19 -04:00
Michael Klishin
3fda07999d An typo 2014-05-11 13:39:37 -04:00
Michael Klishin
6f93043eab Another session store test suite now passes 2014-05-11 13:38:44 -04:00
Michael Klishin
d7965adb86 Remove tests that are now duplicates 2014-05-11 13:37:18 -04:00
Michael Klishin
9a185596ac Clojure [Ring] session store tests now pass 2014-05-11 13:35:53 -04:00
Michael Klishin
31ebc18c12 Ragtime integration tests now pass 2014-05-11 13:32:22 -04:00
Michael Klishin
eaa66edc93 Cosmetics 2014-05-11 13:30:36 -04:00
Michael Klishin
03e7bfa1c7 Query operator tests now pass 2014-05-11 13:30:12 -04:00
Michael Klishin
431e4495af Typo 2014-05-11 13:27:41 -04:00
Michael Klishin
b3c501a73a Inserting tests now pass 2014-05-11 13:26:27 -04:00
Michael Klishin
c29587f66d Cursor tests now pass 2014-05-11 13:19:19 -04:00
Michael Klishin
6acfb43314 Collection op tests now pass 2014-05-11 13:17:14 -04:00
Michael Klishin
f02a2b0afc Capped collection tests now pass 2014-05-11 13:12:30 -04:00
Michael Klishin
d7902c9618 Query DSL tests now pass 2014-05-11 13:10:56 -04:00
Michael Klishin
565ec43398 Atomic modifiers tests now pass 2014-05-11 12:59:15 -04:00
Michael Klishin
60a419953f Remove an unused import 2014-05-11 12:59:08 -04:00
Michael Klishin
c64f5a66d9 Updating test now passes 2014-05-11 12:50:21 -04:00
Michael Klishin
9752950d82 Add extra arities to several update functions 2014-05-11 12:50:15 -04:00
Michael Klishin
37e8df8300 And even fewer 2014-05-11 12:42:33 -04:00
Michael Klishin
f0722561c3 Run fewer cycles
Saves laptop batter while I'm on this flight, yo.
2014-05-11 12:42:23 -04:00
Michael Klishin
c75b02814d Stress test now passes 2014-05-11 12:36:14 -04:00
Michael Klishin
eddc8b20bd Regular finders tests now pass 2014-05-10 18:05:25 -04:00
Michael Klishin
353df3b841 monger.result tests now pass 2014-05-10 17:55:38 -04:00
Michael Klishin
a3954f3847 Require options in monger.collection to be maps (pseudo-kwargs are no longer supported) 2014-05-10 17:55:28 -04:00
Michael Klishin
58d426d6aa Map/Reduce tests now pass 2014-05-10 17:50:03 -04:00
Michael Klishin
5fb665e5eb Don't use removed test helper here 2014-05-10 17:49:55 -04:00
Michael Klishin
b1e874aa87 monger.fn can go now since we rely on ClojureWerkz Support 2014-05-10 17:43:43 -04:00
Michael Klishin
c6ef174535 monger.test.indexing-test now passes 2014-05-10 17:39:39 -04:00
Michael Klishin
56eebda3fd GridFS tests now pass, plus API improvements that make sense for 2.0 2014-05-10 17:34:22 -04:00
Michael Klishin
a7cceebe9c Search tests now pass 2014-05-10 17:04:55 -04:00
Michael Klishin
8b237db382 Cosmetics 2014-05-10 17:04:38 -04:00
Michael Klishin
42ca0efa5c Cosmetics 2014-05-10 17:04:28 -04:00
Michael Klishin
912b9e4d45 monger.db tests now pass 2014-05-10 16:57:42 -04:00
Michael Klishin
d3cb048d2b monger.core tests now pass 2014-05-10 16:52:44 -04:00
Michael Klishin
d114073413 monger.command tests now pass 2014-05-10 16:48:32 -04:00
Michael Klishin
ab4a9a381f Compile 2014-05-10 16:48:25 -04:00
Michael Klishin
d99b6c52aa monger.cache tests now pass 2014-05-10 16:45:36 -04:00
Michael Klishin
d76127de49 Authentication and URI connection tests now pass 2014-05-10 16:36:19 -04:00
Michael Klishin
e04c694e3c monger.core/authenticate should not require a connection 2014-05-10 16:35:58 -04:00
Michael Klishin
b0cd0bf671 Aggregation framework tests now pass 2014-05-10 16:28:02 -04:00
Michael Klishin
9ad38a9e7a Require connection/db/gridfs as an explicit argument (initial pass) 2014-05-10 16:27:52 -04:00
Michael Klishin
04e6c5bce6 Get rid of monger.multi, the entire API will now require a conn/db/gridfs arg 2014-05-10 16:27:28 -04:00
Michael Klishin
1e9463e466 Remove testkit 2014-05-10 16:26:59 -04:00
Michael Klishin
7766475e52 Remove old test helpers 2014-05-10 16:26:51 -04:00
Michael Klishin
5b1d063301 1.8.0 is out 2014-05-09 17:14:08 -04:00
Michael Klishin
1cae021b47 Update change log 2014-05-09 17:13:45 -04:00
Michael Klishin
9c2aa45b75 Back to dev version 2014-05-09 17:13:22 -04:00
Michael Klishin
d78c0d45c8 1.8.0 2014-05-09 17:10:12 -04:00
Michael Klishin
4b61275814 Next release will be 1.8.0 2014-05-09 17:10:05 -04:00
Michael Klishin
6a15f6959e Ditto 2014-05-09 17:08:44 -04:00
Michael Klishin
58015b4f40 Ditto 2014-05-09 17:08:37 -04:00
Michael Klishin
c0ef0ab7c8 Ditto 2014-05-09 17:08:34 -04:00
Michael Klishin
a7ccfbecab Ditto 2014-05-09 17:08:31 -04:00
Michael Klishin
ca40889348 Ditto 2014-05-09 17:08:27 -04:00
Michael Klishin
63168d68f5 Ditto 2014-05-09 17:08:24 -04:00
Michael Klishin
1991308567 Ditto 2014-05-09 17:08:21 -04:00
Michael Klishin
bf0f20e0d9 Ditto 2014-05-09 17:08:18 -04:00
Michael Klishin
a0e4c9ea93 Ditto 2014-05-09 17:08:16 -04:00
Michael Klishin
2d77d1ba27 Ditto 2014-05-09 17:08:14 -04:00
Michael Klishin
e240e906b0 Ditto 2014-05-09 17:08:11 -04:00
Michael Klishin
8a4c497ea7 Ditto 2014-05-09 17:08:09 -04:00
Michael Klishin
de377f3849 Don't set compiler reflection warnings here, it's done by Lein 2 now 2014-05-09 17:08:05 -04:00
Michael Klishin
ed23f7d9fc Use Validateur 2.1.0 2014-05-09 17:05:49 -04:00
Michael Klishin
31bcb51ee4 Use separate collections for these tests
Make tests pass on MongoDB 2.6.
2014-05-09 17:04:54 -04:00
Michael Klishin
b86cabdc1a One more assertion 2014-05-09 17:01:02 -04:00
Michael Klishin
373c4db7a4 Greatly speed up monger.multi.* tests, esp. with MongoDB 2.6 2014-05-09 16:58:33 -04:00
Michael Klishin
6d3b2be339 Depend on MongoDB Java driver 2.12.1 2014-04-30 00:47:44 +04:00
Michael Klishin
6fd331da15 Update change log 2014-03-27 18:14:09 +04:00
Michael Klishin
7bb90ac86a 1.5 is an extra profile now 2014-03-27 18:13:34 +04:00
Michael Klishin
2e64a24cc7 Depend on Clojure 1.6 2014-03-27 18:13:10 +04:00
Michael Klishin
87637dd6fe Master is now 1.7 snapshot 2014-03-27 09:31:48 +04:00
Michael Klishin
f413016ef0 Test against 1.6.0 (final) 2014-03-25 18:11:23 +04:00
Michael Klishin
6009e6e719 Test against 1.6.0-RC4 2014-03-24 21:33:22 +04:00
Michael Klishin
209272fb6c Test against 1.6.0-RC2 2014-03-22 10:14:39 +04:00
Michael Klishin
9b5f8de1f3 Should be RC1 (capitals) 2014-03-11 23:02:50 +04:00
Michael Klishin
eaf07fcf41 Test against Clojure 1.6.0-rc1 2014-03-11 22:43:37 +04:00
Michael Klishin
18ce852146 Correct Codox version 2014-03-08 14:58:44 +04:00
Michael Klishin
db6715b282 bump Codox 2014-03-08 14:53:21 +04:00
Michael Klishin
f5d87d0aaa Make sure field parameters are in the correct order 2014-03-02 21:34:54 +04:00
Michael Klishin
555ac53d22 Introduce a way to run "raw" commands (using DBObjects) 2014-03-02 21:31:26 +04:00
Michael Klishin
413d4484b8 Update this test 2014-03-02 21:02:59 +04:00
Michael Klishin
4b417ec15a Mention that monger.result should no longer be used on WriteConcern instances as of 1.8 2014-03-02 14:57:25 +04:00
Michael Klishin
3728f38ad7 Change log updates 2014-03-02 14:57:08 +04:00
Michael Klishin
4c1a4f9505 Update change log 2014-03-02 14:49:08 +04:00
Michael Klishin
b66abf5a2c Depend on MongoDB Java client 2.12.0-rc0 2014-03-02 14:48:24 +04:00
Michael Klishin
e362d32b3a Update this test for 2.12.x 2014-03-02 14:48:15 +04:00
Michael Klishin
4dac6375ed Update change log 2014-03-02 14:41:14 +04:00
Michael Klishin
5d5c5dbced Change default write concern to ACKNOWLEDGED
Recommended by MongoDB docs, also forward compatibility with MongoDB 2.6.
2014-03-02 14:39:19 +04:00
Michael Klishin
b4472e7167 Cosmetics 2014-03-02 14:35:43 +04:00
Michael Klishin
84e76c1e30 Cosmetics 2014-03-02 14:35:01 +04:00
Michael Klishin
c334f206ed $mul operator 2014-03-02 14:33:01 +04:00
Michael Klishin
5a88eb89f7 Bump Validateur to 2.0 2014-03-02 14:31:44 +04:00
Michael Klishin
01e3ad7977 $text is an operator in 2.6 2014-03-02 14:29:32 +04:00
Michael Klishin
6671cb123f Test against 1.6.0-beta2 2014-03-01 17:25:22 +04:00
Michael Klishin
f04638348c Back to dev version 2014-02-28 20:00:31 +04:00
Michael Klishin
248e177a6c 1.8.0-beta1 2014-02-28 19:58:05 +04:00
Michael Klishin
60bb6480b4 Merge pull request #73 from MichaelDrogalis/master
Removes uneeded AOT compilation.
2014-02-24 16:19:01 +03:00
Michael Drogalis
7bdc3994dd Removes uneeded AOT compilation. 2014-02-24 08:17:25 -05:00
Michael Klishin
2d1ab796ba Test against 1.6.0-beta1 2014-02-15 13:47:14 +04:00
Michael Klishin
3c951a0828 Sync with upstream
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2014-02-08 19:02:02 +04:00
Michael Klishin
0c1fec027d ditto 2014-02-08 19:01:41 +04:00
Michael Klishin
276f0f81d9 ditto 2014-02-08 19:01:37 +04:00
Michael Klishin
f1f46b6983 ditto 2014-02-08 19:01:34 +04:00
Michael Klishin
6758a1d102 ditto 2014-02-08 19:01:30 +04:00
Michael Klishin
4b6ddc5289 ditto 2014-02-08 19:01:27 +04:00
Michael Klishin
d3aedaec03 ditto 2014-02-08 19:01:24 +04:00
Michael Klishin
286a9dc10e ditto 2014-02-08 19:01:20 +04:00
Michael Klishin
bb058bf19a ditto 2014-02-08 19:01:17 +04:00
Michael Klishin
05e7d3727d ditto 2014-02-08 19:01:14 +04:00
Michael Klishin
e065db51d3 ditto 2014-02-08 19:01:11 +04:00
Michael Klishin
5022eeaf4c ditto 2014-02-08 19:01:08 +04:00
Michael Klishin
2bafefd3f3 ditto 2014-02-08 19:01:05 +04:00
Michael Klishin
b2e34e1f57 ditto 2014-02-08 19:01:02 +04:00
Michael Klishin
aa0347cd2e ditto 2014-02-08 19:00:59 +04:00
Michael Klishin
a6912c9db1 ditto 2014-02-08 19:00:56 +04:00
Michael Klishin
962e4c8313 ditto 2014-02-08 19:00:52 +04:00
Michael Klishin
371a209ae3 ditto 2014-02-08 19:00:50 +04:00
Michael Klishin
06be43a8c1 ditto 2014-02-08 19:00:47 +04:00
Michael Klishin
409b13a9fb ditto 2014-02-08 19:00:43 +04:00
Michael Klishin
04d92f35cd ditto 2014-02-08 19:00:40 +04:00
Michael Klishin
7d41ffc47c (c) header 2014-02-08 19:00:38 +04:00
Michael Klishin
bd575126a3 Update ChangeLog.md 2014-02-02 01:27:32 +03:00
Michael Klishin
c163283d22 Merge pull request #72 from myfreeweb/patch-1
Add non-bang version of connect-via-uri
2014-01-30 11:07:54 -08:00
Greg V
47efed8260 Add non-bang version of connect-via-uri 2014-01-30 18:58:36 +03:00
Michael Klishin
047dfeaafa Sync with upstream 2014-01-17 03:08:23 +04:00
Michael Klishin
78eaeebae8 Merge pull request #70 from seancorfield/master
Requiring monger.cursor without requiring monger.core fails
2014-01-16 00:33:46 -08:00
Sean Corfield
3ceecf4e0c Merge branch 'master' of github.com:michaelklishin/monger 2014-01-15 18:42:31 -08:00
Sean Corfield
6db4eab95c Merge branch 'master' of github.com:seancorfield/monger 2014-01-15 18:41:08 -08:00
Sean Corfield
daace7283c monger.cursor uses monger.core but did not require it first. 2014-01-15 18:41:02 -08:00
Michael Klishin
e37872bbca Assorted updates to dev dependencies 2014-01-12 18:44:01 +04:00
Michael Klishin
c2a13a1645 Merge pull request #69 from seancorfield/master
Use local binding instead of dynamic global for collection. Fixes #68
2014-01-12 00:38:56 -08:00
Sean Corfield
cb47b7541e Use local binding instead of dynamic global for collection. Fixes #68 2014-01-11 15:57:27 -08:00
Michael Klishin
ebe63865bd Drop Clojure 1.3 support mention 2014-01-11 14:21:16 +04:00
Michael Klishin
131437d28f Update README 2014-01-11 14:20:59 +04:00
Michael Klishin
776f33a83e Back to dev version 2014-01-11 14:19:59 +04:00
Michael Klishin
befb852659 1.7.0 2014-01-11 14:18:36 +04:00
Michael Klishin
c5a3c583f2 Bump Support 2014-01-11 14:18:24 +04:00
Michael Klishin
94d2480b9e Update change log 2014-01-10 20:54:51 +04:00
Michael Klishin
0522b2cf71 Make Ragtime dependency optional 2014-01-10 20:54:03 +04:00
Michael Klishin
b5748782ef Update change log 2014-01-10 20:53:38 +04:00
Michael Klishin
dd1e475ea4 Update MongoDB Java driver to 2.11.3 2014-01-10 20:53:04 +04:00
Michael Klishin
5e51a78d6a Update change log 2014-01-10 20:51:59 +04:00
Michael Klishin
c76ea84412 Make Validateur dependency optional 2014-01-10 20:49:53 +04:00
Michael Klishin
d2f334ca85 Sync with upstream 2014-01-05 18:43:05 +04:00
Michael Klishin
7810732608 Update copyright year 2013-12-31 18:17:39 +04:00
Michael Klishin
ff2e6cc220 Merge pull request #66 from bitdeli-chef/master
Add a Bitdeli Badge to README
2013-12-18 02:03:34 -08:00
Bitdeli Chef
8fb51475f0 Add a Bitdeli badge to README 2013-12-18 10:05:08 +00:00
Michael Klishin
3083a18191 Merge pull request #65 from mlni/add_first_and_last_operators
Added support for $first and $last aggregation operators.
2013-12-04 12:05:26 -08:00
Matti Jagula
c81026e308 Added support for $first and $last aggregation operators. 2013-12-04 21:43:40 +02:00
Michael Klishin
568ba283c8 Ditto 2013-11-30 23:46:45 +04:00
Michael Klishin
0755c0c4b1 ws 2013-11-30 23:46:34 +04:00
Michael Klishin
0f773b8dfe Ditto 2013-11-30 23:46:12 +04:00
Michael Klishin
938c440764 Don't use :use 2013-11-30 23:45:29 +04:00
Michael Klishin
ea5e1a3b9c Don't use :use 2013-11-30 23:45:02 +04:00
Michael Klishin
d380321e2e Cosmetics 2013-11-30 23:44:40 +04:00
Michael Klishin
8837fb46b9 Cosmetics 2013-11-30 23:44:21 +04:00
Michael Klishin
e540d453a0 Don't use :use 2013-11-30 23:43:50 +04:00
Michael Klishin
12c33ac975 Cosmetics 2013-11-30 23:43:23 +04:00
Michael Klishin
3d89d02e9d Docstring 2013-11-30 23:43:02 +04:00
Michael Klishin
496435c350 Don't use :use 2013-11-30 23:42:42 +04:00
Michael Klishin
b8d5b27054 Cosmetics 2013-11-30 23:42:25 +04:00
Michael Klishin
5c82651bde Docstring 2013-11-30 23:41:55 +04:00
Michael Klishin
cbf198c8bd Cosmetics 2013-11-30 23:41:32 +04:00
Michael Klishin
5d67b374fc Don't use :use 2013-11-30 23:41:12 +04:00
Michael Klishin
61a76bfd1c Don't use :use 2013-11-30 23:40:17 +04:00
Michael Klishin
c23e019ccd Cosmetics 2013-11-30 23:39:48 +04:00
Michael Klishin
30da676626 Docstring 2013-11-30 23:39:25 +04:00
Michael Klishin
109aef0645 Ditto 2013-11-30 23:38:46 +04:00
Michael Klishin
41375af05f Don't use :use 2013-11-30 23:38:22 +04:00
Michael Klishin
19ab7eb8a7 Cosmetics 2013-11-30 23:37:50 +04:00
Michael Klishin
118a6aa872 Cosmetics 2013-11-30 23:37:26 +04:00
Michael Klishin
6ba204a602 Ditto 2013-11-30 20:16:18 +04:00
Michael Klishin
02121379e7 Don't use :use 2013-11-30 20:16:04 +04:00
Michael Klishin
daa8361c91 Cosmetics 2013-11-30 20:15:41 +04:00
Michael Klishin
56bcf8c209 Copy year 2013-11-30 20:15:17 +04:00
Michael Klishin
a2beed97e7 Cosmetics 2013-11-30 20:15:04 +04:00
Michael Klishin
4201107a0a Ditto 2013-11-30 20:04:09 +04:00
Michael Klishin
23300cf73c Ditto 2013-11-30 20:03:42 +04:00
Michael Klishin
de4eb78d83 Ditto 2013-11-30 20:03:22 +04:00
Michael Klishin
d4ea338f19 Cosmetics 2013-11-30 20:03:03 +04:00
Michael Klishin
0cbde38d77 Ditto 2013-11-30 20:02:59 +04:00
Michael Klishin
4e0548c151 Ditto 2013-11-30 20:02:17 +04:00
Michael Klishin
1e9f915921 Ditto 2013-11-30 20:02:02 +04:00
Michael Klishin
db79ec0079 Ditto 2013-11-30 20:01:42 +04:00
Michael Klishin
18d924317d Ditto 2013-11-30 20:01:26 +04:00
Michael Klishin
635436a438 Ditto 2013-11-30 20:00:52 +04:00
Michael Klishin
2d43975ce3 Ditto 2013-11-30 20:00:37 +04:00
Michael Klishin
6cd615ea97 Ditto 2013-11-30 20:00:20 +04:00
Michael Klishin
790fc63f7c Ditto 2013-11-30 19:59:26 +04:00
Michael Klishin
08887043db Ditto 2013-11-30 19:58:46 +04:00
Michael Klishin
01ae26ff2b Ditto 2013-11-30 19:53:48 +04:00
Michael Klishin
af262d3b82 Ditto 2013-11-30 19:53:16 +04:00
Michael Klishin
490aaa3dad Ditto 2013-11-30 19:48:35 +04:00
Michael Klishin
57348f0650 Ditto 2013-11-30 19:48:32 +04:00
Michael Klishin
c110553be9 Ditto 2013-11-30 19:48:25 +04:00
Michael Klishin
646e75ddf4 Ditto 2013-11-30 14:58:44 +04:00
Michael Klishin
eb0a257d8f Ditto 2013-11-30 14:57:53 +04:00
Michael Klishin
3e6d65e837 Ditto 2013-11-30 14:52:31 +04:00
Michael Klishin
e4ec4fc351 Ditto 2013-11-30 14:51:57 +04:00
Michael Klishin
bba5cc50c6 Ditto 2013-11-30 14:22:24 +04:00
Michael Klishin
b476562edc Ditto 2013-11-30 14:21:55 +04:00
Michael Klishin
47b14ee8a1 Ditto 2013-11-30 14:21:36 +04:00
Michael Klishin
251f6fc765 Ditto 2013-11-30 14:21:12 +04:00
Michael Klishin
0dca29285c Ditto 2013-11-30 14:20:37 +04:00
Michael Klishin
19d0058c53 Ditto 2013-11-30 14:20:16 +04:00
Michael Klishin
141380dd26 Ditto 2013-11-30 14:19:50 +04:00
Michael Klishin
1da5f64b91 Ditto 2013-11-30 14:19:25 +04:00
Michael Klishin
9760e88b66 Ditto 2013-11-30 14:18:55 +04:00
Michael Klishin
a2ff58f4f4 Ditto 2013-11-30 14:18:24 +04:00
Michael Klishin
b24517e648 Ditto 2013-11-30 14:17:48 +04:00
Michael Klishin
65e6310758 Don't use :use 2013-11-30 14:17:24 +04:00
Michael Klishin
a468f75a7c Don't use :use 2013-11-30 14:14:06 +04:00
Michael Klishin
bb5a57b468 This feature has long been a part of a stable release 2013-11-30 03:52:39 +04:00
Michael Klishin
b72968dfb9 README updates 2013-09-25 18:12:12 +04:00
Michael Klishin
4371e64d86 Back to dev version 2013-09-25 18:11:54 +04:00
Michael Klishin
0e6685ee28 Change log update 2013-09-25 01:28:00 +04:00
Michael Klishin
19d2d97d78 1.7.0-beta1 2013-09-25 01:15:22 +04:00
Michael Klishin
3d120456ff Merge pull request #62 from timgluz/query_options
Enhancements for tweaking options of dbCursor
2013-09-21 13:04:48 -07:00
Timo Sulg
7e7f3aba4c cleanups; updated query/option; 2013-09-21 19:17:58 +02:00
Timo Sulg
2dca992496 added cursor namespaces, cleanups;
refactored helpers for DBCursor into own namespace;
cleaned up previous hacks;
added extra classes for add-options;
added tests for cursor namespace;
2013-09-21 15:46:01 +02:00
Michael Klishin
b1f4e09a7c Change log update 2013-09-15 21:13:21 +01:00
Michael Klishin
bc1408806f Support 0.20 2013-09-15 21:13:02 +01:00
Michael Klishin
5046d0abc4 Update change log 2013-09-15 21:12:39 +01:00
Michael Klishin
7890c94496 Merge pull request #61 from timgluz/local_date
Added support for LocalDate - required for serializing clj-time/today objects.
2013-09-15 12:14:09 -07:00
Timo Sulg
58b5b1ddac updated docs; additional buffertime for timeout. 2013-09-15 20:30:01 +02:00
Timo Sulg
7570e4ce6d Added cursor-helpers and new find method; 2013-09-15 16:53:41 +02:00
Timo Sulg
b57c97a962 fixed tests for LocalDate - now tests components of date separately. 2013-09-11 16:29:59 +02:00
Timo Sulg
7b3869ec04 Moved localdate tests into lib_integration_test. 2013-09-11 14:51:35 +02:00
Michael Klishin
3a30373d94 Drop Clojure 1.3 support
It still works with 1.3 but we will no longer try to support it.
2013-09-10 20:54:32 +01:00
Michael Klishin
ca6a128c91 Change log updates 2013-09-10 20:53:35 +01:00
Michael Klishin
8d53ca73e7 Bump clj-time 2013-09-10 20:51:14 +01:00
Michael Klishin
a3c5159223 Bump ring.core 2013-09-10 20:50:42 +01:00
Michael Klishin
41089c1da8 Bump core.cache 2013-09-10 20:50:34 +01:00
Michael Klishin
a31097fc86 Bump Cheshire 2013-09-10 20:50:27 +01:00
Michael Klishin
3b846551a3 Bump tools.cli 2013-09-10 20:50:17 +01:00
Michael Klishin
3f9cb9bb59 Bump Support 2013-09-10 20:50:08 +01:00
Michael Klishin
bed9b035b7 Bump Ragtime 2013-09-10 20:50:01 +01:00
Michael Klishin
e9898cdbbe Bump validateur 2013-09-10 20:49:54 +01:00
Timo Sulg
679fd2bf92 Added support for LocalDate - required for serializing (clj-time/today). 2013-09-10 17:54:37 +02:00
Michael Klishin
957650dfe3 Run CI against a single Clojure version for now
Some compilation artifacts are not cleared on travis :/
2013-08-17 18:04:38 +04:00
Michael Klishin
3801c37f51 This section is about baseline performance
and highly unscientific, too
2013-08-17 17:56:52 +04:00
Michael Klishin
182a82315f Make our README less backwards
Getting Started & Documentation should go before Community/Support
2013-08-17 17:55:15 +04:00
Michael Klishin
adc5038259 README updates 2013-07-07 16:03:57 +04:00
Michael Klishin
ea493eee1d Back to dev version 2013-07-06 14:48:11 +04:00
Michael Klishin
b58a812c18 1.6.0 2013-07-06 14:44:59 +04:00
Michael Klishin
78c9336ad7 Merge branch 'master' of github.com:michaelklishin/monger
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2013-07-06 04:38:56 +04:00
Michael Klishin
f37db1fa84 Correct type hints 2013-07-06 04:38:05 +04:00
Michael Klishin
a33128791b Merge pull request #58 from code54/fix-ragtime-migrations-ordering
New ragtime version. ChangeLog for fix on `applied-migration-ids` ordering
2013-07-05 13:08:48 -07:00
Fernando Dobladez
080c17f175 New ragtime version 0.3.3. ChangeLog for fix on applied-migration-ids ordering 2013-07-05 16:57:23 -03:00
Michael Klishin
cabd7178aa Merge pull request #57 from code54/fix-ragtime-migrations-ordering
Fix:  must return ids in creation order
2013-07-05 12:44:23 -07:00
Fernando Dobladez
0179bbc046 Fix: must return ids in creation order 2013-07-05 16:21:35 -03:00
Michael Klishin
a04596cdc5 Merge pull request #56 from ebaxt/session-store
Made it possbile to pass explisit db to session-store
2013-07-04 13:26:01 -07:00
Erik Bakstad
54f204b1a5 Renamed test 2013-06-24 00:25:58 +02:00
Erik Bakstad
a6606deb05 Made it possbile to pass explisit db to session-store 2013-06-24 00:17:48 +02:00
Michael Klishin
8ea1681519 Back to dev version 2013-06-23 23:17:30 +04:00
Michael Klishin
67111ce764 1.6.0-beta3 2013-06-23 23:16:02 +04:00
Michael Klishin
a53ee10e41 Upgrade MongoDB Java driver to 2.11.2 2013-06-23 23:15:48 +04:00
Michael Klishin
8c58ab0155 Change log update 2013-06-23 23:14:24 +04:00
Michael Klishin
c0f1112d34 Merge pull request #55 from ebaxt/multi
Finished multi.collection
2013-06-23 05:58:46 -07:00
Erik Bakstad
0a03ec1bf8 Added rest of tests. Fixes #53 2013-06-22 20:20:59 +02:00
Erik Bakstad
41c2aa7488 Added multi.collection-tests 2013-06-20 19:56:26 +02:00
Erik Bakstad
fd5e041099 Fixed test issues when running all tests 2013-06-20 19:41:02 +02:00
Erik Bakstad
6a9cb9f1a3 Don't run fin_test on ns load 2013-06-20 19:11:52 +02:00
Erik Bakstad
0d635721a1 Added missing fns to multi/collection. Related to #53. 2013-06-20 13:25:27 +02:00
Michael Klishin
7cc7b3a2d5 Merge pull request #54 from ikitommi/setOnInsert
$setOnInsert operator
2013-06-19 21:49:24 -07:00
Tommi Reiman
4137f4a6f9 $setOnInsert 2013-06-20 00:01:28 +03:00
Michael Klishin
3bc3ee6d6a Add $millisecond to monger.operators 2013-05-27 05:21:25 +04:00
Michael Klishin
af19e62479 Add $slice to the list of known operators 2013-05-14 15:00:53 +04:00
Michael Klishin
4ac8f8330a Initial work on monger.multi.collection 2013-04-19 00:43:27 +04:00
Michael Klishin
48be8602e3 Back to snapshot 2013-04-17 02:28:01 +04:00
Michael Klishin
2b26d74d9b 1.6.0-beta2 2013-04-17 02:27:01 +04:00
Michael Klishin
957623094b Clear cache collections in the correct db 2013-04-17 02:26:42 +04:00
Michael Klishin
0a386750c3 Clear cache collections 2013-04-17 02:22:57 +04:00
Michael Klishin
a39c13a574 Make monger.collection/upsert actually upsert
Headdesk
2013-04-17 02:01:22 +04:00
Michael Klishin
bdf0082372 Merge branch 'master' of github.com:michaelklishin/monger 2013-04-15 21:24:13 +04:00
Michael Klishin
c0a83e7241 Add monger.collection/upsert 2013-04-15 21:24:08 +04:00
Michael Klishin
0bee6bed9e Back to snapshot 2013-04-15 03:41:13 +04:00
Michael Klishin
f40161f035 1.6.0-beta1 2013-04-15 03:40:18 +04:00
Michael Klishin
6794759da1 Merge pull request #52 from jafingerhut/master
Eliminate some reflection via adding type hints, and correcting one
2013-04-13 16:23:16 -07:00
Andy Fingerhut
0bd3ef12ab Eliminate some reflection via adding type hints, and correcting one 2013-04-13 16:18:22 -07:00
Michael Klishin
d5b0e2c8be Correct change log 2013-04-14 02:04:27 +04:00
Michael Klishin
bffb58cc1f Introduce additional cache implementation that can use any database 2013-04-14 01:53:56 +04:00
Michael Klishin
c001ab3610 Minor README update 2013-04-07 22:34:47 +04:00
Michael Klishin
85d392b4c7 Add contributing.md 2013-04-07 00:37:08 +04:00
Michael Klishin
9c529cd6c7 Double EPL/APL2 license 2013-04-04 23:51:46 +04:00
Michael Klishin
b7660bec6d update copy year 2013-04-04 23:51:29 +04:00
Michael Klishin
496325a417 Use clojure.core/array-map with ensure-index in all examples
To preserve ordering which is important.

References #50
2013-04-04 23:44:58 +04:00
Michael Klishin
51bb055936 Update README 2013-03-30 00:32:30 +04:00
Michael Klishin
9373550439 Ignore all .lein-* files 2013-03-30 00:32:20 +04:00
Michael Klishin
aff15fdf9a Back to snapshot 2013-03-30 00:31:48 +04:00
Michael Klishin
49a672946d 1.5.0 2013-03-30 00:29:28 +04:00
Michael Klishin
879a0232b0 Remove obsoleted change log entry 2013-03-21 02:05:01 +04:00
Michael Klishin
b7604e44ab Now working on rc2 2013-03-20 04:15:16 +04:00
Michael Klishin
27773f0f76 1.5.0-rc1 2013-03-20 04:11:30 +04:00
Michael Klishin
c7f9f09278 README corrections 2013-03-20 04:11:16 +04:00
Michael Klishin
9e99933c53 Make tests compile with the 2.11 Java driver 2013-03-20 04:08:24 +04:00
Michael Klishin
6b9c5d8f3d Mention new admin database functions in the change log 2013-03-20 03:52:01 +04:00
Michael Klishin
006e89d74a Upgrade MongoDB Java driver to 2.11 2013-03-20 03:50:38 +04:00
Michael Klishin
848bbd07d3 Full text search support via monger.search 2013-03-20 03:50:27 +04:00
Michael Klishin
2a34be05ad Add a few new MongoDB 2.4-specific operators to monger.operators 2013-03-20 01:30:11 +04:00
Michael Klishin
0c25f254b2 Back to snapshot 2013-03-18 19:35:17 +04:00
Michael Klishin
7e090f45d9 1.5.0-beta3 2013-03-18 19:34:20 +04:00
Michael Klishin
1755c977ba Change log update 2013-03-18 19:33:21 +04:00
Michael Klishin
3a2afd0cec Make monger.core/mongo-options fully up-to-date with the Java driver 2.10.1 2013-03-18 19:32:03 +04:00
Michael Klishin
e8e9147e85 Correct change log 2013-03-17 21:02:08 +04:00
Michael Klishin
e20f338505 Don't recommend any specific replacement 2013-03-17 21:01:30 +04:00
Michael Klishin
e9fa768fc6 Change log update 2013-03-17 21:00:36 +04:00
Michael Klishin
2012fed7c4 Finally get rid of the factory DSL
We did learn some things from it but it just did not
work very well. A better solution is coming in the future.
2013-03-17 20:57:40 +04:00
Michael Klishin
3af05ef74c Add a test for m.c/insert-batch with lazy sequence inputs 2013-03-17 19:55:19 +04:00
Michael Klishin
082a3ec7b7 Make this test pass in isolation repeatedly 2013-03-17 19:50:37 +04:00
Michael Klishin
66b94018a6 Now working on beta3-SNAPSHOT 2013-03-17 02:35:21 +04:00
Michael Klishin
6e53b4cba6 1.5.0-beta2 2013-03-17 02:20:19 +04:00
Michael Klishin
6b0f0f8313 Ragtime 0.3.2 2013-03-17 01:36:49 +04:00
Michael Klishin
c933d66b2d Support 0.15 2013-03-17 01:36:44 +04:00
Michael S. Klishin
5d97bf7e4c Clojure 1.5.1, Validateur 1.4.0 2013-03-11 03:09:25 +04:00
Michael Klishin
ec9c57f467 Make sure to clean and recompile version-sensitive Java sources before each CI run 2013-03-08 13:43:16 +04:00
Michael Klishin
1f53145523 Clojure 1.5 by default 2013-03-08 07:01:16 +04:00
Michael Klishin
2c5deb7e59 Test against Clojure 1.5 final, Clojure 1.6 master SNAPSHOT 2013-03-01 20:20:33 +04:00
Michael Klishin
43e40f5f14 Should be use-db! here 2013-02-28 16:46:15 +04:00
Michael Klishin
62013fd070 Introduce 2-arity monger.core/authenticate that authenticates on the default DB 2013-02-28 16:45:34 +04:00
Michael Klishin
d647542d86 Test against Clojure 1.5.0-RC17 2013-02-28 16:35:13 +04:00
Michael Klishin
885a805594 Correct change log 2013-02-21 22:49:10 +04:00
Michael Klishin
7ec9288ecd Back to snapshot 2013-02-21 22:32:05 +04:00
Michael Klishin
f9923c7134 1.5.0-beta1 2013-02-21 22:31:34 +04:00
Michael Klishin
e7c70b8676 Update change log 2013-02-21 22:31:09 +04:00
Michael Klishin
496bc127d8 Use Support 0.14 2013-02-21 22:30:27 +04:00
Michael Klishin
945c71ba56 RC16 2013-02-14 07:47:51 +04:00
Michael Klishin
beaea0bc02 Remove dir-locals for Swank 2013-01-17 03:18:46 +04:00
Michael Klishin
a21fa90834 1.4.2 is out 2013-01-12 22:12:44 +04:00
Michael Klishin
abb82e0b03 Change log update 2013-01-11 11:15:46 +00:00
Michael Klishin
8fd78c3a19 Merge pull request #47 from zussitarze/master
Close DBCurors in find-maps
2013-01-11 03:11:02 -08:00
Tom McNulty
80a4625d89 Close Cursor in queries 2013-01-10 21:01:09 -07:00
Tom McNulty
a121598651 Close DBCursors in find-maps/find-seq 2013-01-10 20:32:48 -07:00
Michael Klishin
175f17af97 Merge branch 'master' of github.com:michaelklishin/monger 2012-12-23 04:05:29 +04:00
Michael Klishin
c6b5f9751e Test against Clojure 1.5.0-RC1 2012-12-23 03:54:58 +04:00
Michael Klishin
8c17da69b5 Merge pull request #46 from rbxbx/patch-1
Correct spelling in monger/collection
2012-12-10 15:20:50 -08:00
Robert Pitts
4bbb26b8dc A few spelling corrections in monger/collection
s/wether/whether/g
2012-12-10 18:16:02 -05:00
Michael Klishin
6194a1604c Cheshire 5.0.1 2012-12-04 19:35:59 +04:00
Michael Klishin
4182a2ab8e Merge branch 'master' of github.com:michaelklishin/monger 2012-12-04 13:06:52 +04:00
Michael Klishin
abc0f2dcbe 1.4.1 is out 2012-12-04 13:06:39 +04:00
Michael Klishin
4a41b34f06 Change log update 2012-12-04 13:06:22 +04:00
Michael Klishin
308124ba97 MongoDB Java driver 2.10.1 2012-12-04 13:05:38 +04:00
Michael Klishin
7ed7e8ae0d Merge pull request #45 from huangz1990/master
Remove duplicated create function in monger.collection
2012-12-01 03:50:26 -08:00
huangz1990
f8a3fe1982 Remove duplicated create function in monger.collection 2012-12-01 19:39:04 +08:00
Michael Klishin
18f2089617 Now working on 1.5.0-SNAPSHOT 2012-11-27 23:35:24 +04:00
Michael Klishin
9c490ebbc1 1.4.0 is out 2012-11-27 23:34:13 +04:00
Michael Klishin
8faf9aec82 Correct MongoDB Java driver version 2012-11-27 23:33:46 +04:00
Michael Klishin
fe0a885d79 1.4.0 2012-11-27 23:30:33 +04:00
Michael Klishin
d3114be395 Upgrade to MongoDB Java driver 2.10
A note on a few test we removed: they are not essential, the implementation still
works fine but MongoDB Java driver is so broken in some areas that it is really
painful to work around all that stuff.

For example, authentication commands fail because the request cannot be
authenticated (!!!). In general, all removed tests involve or related to
authentication failures or edge cases where the database is switched between
tests.

Because authentication with valid credentials works perfectly fine,
it is hard to justify spending another 2 hours working around
issues in the driver that had way too many poor design decisions
from very early days.
2012-11-27 23:25:24 +04:00
Michael Klishin
20faaf2fe0 Eliminate some reflection warnings 2012-11-24 21:11:07 +04:00
Michael Klishin
64bf2eff7f ws 2012-11-23 07:24:28 +04:00
Michael Klishin
28c29a7bae Remove temporary test metadata 2012-11-23 07:24:25 +04:00
Michael Klishin
d8ff844bfa Demonstrate correct ordering when sorting on multiple keys using ordered maps (array-map or sorted-map)
Closes #44
2012-11-23 07:23:36 +04:00
Michael Klishin
e4238710f3 Ditto for tests 2012-11-21 12:03:44 +04:00
Michael Klishin
7a87332537 Changes for Cheshire 5.0 2012-11-21 12:00:18 +04:00
Michael Klishin
f4b4bb0849 Move to Support 0.10: monger.json now requires Cheshire 5.0 2012-11-21 11:57:26 +04:00
Michael Klishin
5d39787825 Codox 0.6.3 2012-11-17 19:49:10 +04:00
Michael S. Klishin
1ae91971d6 Cherry-pick more changes from 1.3.x-stable manually 2012-11-09 02:21:28 +04:00
Michael S. Klishin
09e8adb7bb 1.3.4 is out 2012-11-09 02:21:14 +04:00
Michael S. Klishin
c5e2c78ed0 The same fix for data.json compatibility we had in clojurewerkz.support.json 2012-11-09 02:19:48 +04:00
Michael S. Klishin
47aabed2e4 Support 0.9.0, for real 2012-10-31 02:31:41 +04:00
Michael S. Klishin
cca473eca3 Support 0.9.0 2012-10-31 02:31:15 +04:00
Michael S. Klishin
c8745ccdb8 1.3.2 is out 2012-10-31 02:18:21 +04:00
Michael S. Klishin
3123ce3684 Change log update 2012-10-31 02:11:23 +04:00
Michael S. Klishin
19e0d08269 MongoDB Java driver 2.9.3 2012-10-31 02:04:50 +04:00
Michael S. Klishin
466f09f894 1.3.1 is out 2012-10-24 23:45:43 +04:00
Michael S. Klishin
cd67e7c6b3 Support 0.8.0
Fixes clojurewerkz.support.json compilation when clojure.data.json
is not available.
2012-10-24 23:41:23 +04:00
Michael S. Klishin
adfce471a1 Explain that Cheshire or clojure.data.json now need to be added as explicit app dependencies 2012-10-24 23:01:30 +04:00
Michael S. Klishin
54c8c5f791 1.3.0 is out, begin 1.4.0 development cycle 2012-10-24 08:00:27 +04:00
Michael S. Klishin
1f0414e06b Back to snapshot 2012-10-24 07:59:33 +04:00
Michael S. Klishin
9fe01a7f58 1.3.0 2012-10-24 07:58:11 +04:00
Michael S. Klishin
2818ac6c26 Introduce monger.core/disconnect!
Closes #42
2012-10-24 07:57:09 +04:00
Michael S. Klishin
2fb74c6aff MongoDB Java driver 2.9.2 2012-10-24 07:53:33 +04:00
Michael S. Klishin
53fabbab73 Add .dir-locals.el that assumes Leiningen 2 is available at ~/bin/lein 2012-10-15 14:32:37 +04:00
Michael S. Klishin
1a351cff88 Use and recommend sorted maps for commands 2012-09-19 16:34:24 +04:00
Michael S. Klishin
1d179d9185 Tidy up project.clj 2012-09-16 17:04:26 +04:00
Michael S. Klishin
76b3371420 Cosmetics 2012-09-14 11:46:48 +04:00
Michael S. Klishin
113ee02048 Don't use deprecated constant 2012-09-14 11:42:56 +04:00
Michael S. Klishin
c8e17e2c7a Be honest 2012-09-11 18:56:16 +04:00
Michael S. Klishin
7095955555 Update change log 2012-09-10 11:30:23 +04:00
Michael S. Klishin
07b76a307c Update Ragtime 2012-09-10 11:00:16 +04:00
Michael S. Klishin
c3b5759ce4 Update MongoDB Java driver to 2.9.1 2012-09-10 11:00:10 +04:00
Michael S. Klishin
1fcac25c17 README update 2012-09-07 01:10:35 +04:00
Michael S. Klishin
33b8f54460 Cheshire support for monger.json and monger.joda-time 2012-09-07 00:48:18 +04:00
Michael S. Klishin
23a55420df Work arounds for CLJ-1062 2012-09-06 05:54:28 +04:00
Michael S. Klishin
cf86bd4ab6 Changes in CLJ-940 breaks CI (ns compilation) against 1.5.0-SNAPSHOT, disable it until we have the time to investigate 2012-09-06 05:15:02 +04:00
Michael S. Klishin
d0b5a412c9 Ignore target/* 2012-09-06 04:43:08 +04:00
Michael S. Klishin
53a0ef78fd Back to SNAPSHOT 2012-08-29 17:52:12 +04:00
Michael S. Klishin
a5ec7c5662 Update change log 2012-08-29 17:50:17 +04:00
70 changed files with 5141 additions and 3976 deletions

12
.gitignore vendored
View file

@ -1,10 +1,16 @@
pom.xml
pom.xml*
*jar
/lib/
/classes/
.lein-failures
.lein-deps-sum
.lein-*
TAGS
checkouts/*
doc/*
deploy.docs.sh
target/*
todo.org
.nrepl-*
.idea/
*.iml
/.clj-kondo/.cache
/.lsp/.cache

View file

@ -1,11 +1,20 @@
language: clojure
lein: lein2
sudo: required
lein: lein
dist: xenial
before_script:
# Give MongoDB server some time to boot
- sleep 15
- mongod --version
- ./bin/ci/before_script.sh
script: lein2 javac && lein2 all test
script: lein do clean, javac, test
jdk:
- openjdk6
- openjdk7
- oraclejdk7
- openjdk10
- oraclejdk11
- openjdk12
services:
- mongodb
branches:
only:
- master
- 3.5.x-stable

13
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,13 @@
## Pre-requisites
The project uses [Leiningen 2](http://leiningen.org) and requires a recent MongoDB to be running
locally. Make sure you have those two installed and then run tests against all supported Clojure versions using
./bin/ci/before_script.sh
lein all do clean, javac, 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.

View file

@ -1,6 +1,563 @@
## Changes between 1.2.0 and 1.2.1
## Changes between 3.5.x and 3.6.0 (unreleased)
### UUID Representation Option
Added a new connection option, `:uuid-representation`.
Contributed by @okorz001.
GitHub issue: [#212](https://github.com/michaelklishin/monger/issues/212)
### Operator List Update
For MongoDB 4.x.
Contributed by @mjrb.
GitHub issue: [#196](https://github.com/michaelklishin/monger/pull/196)
### Dependency Update
Contributed by @robhanlon22.
GitHub issue: [#206](https://github.com/michaelklishin/monger/pull/206)
## Changes between 3.1.x and 3.5.0 (Dec 10th, 2018)
### MongoDB Java Driver Update
MongoDB Java driver dependency has been updated to `3.9.x`.
This means that Monger now **requires JDK 8**.
Contributed by @Linicks.
### 3rd Party Library Compatibility
* Cheshire `5.8.x`
* clj-time `0.15.1`
* ring-core `0.15.1`
* Ragtime `0.7.x`.
### URI Connection Usability Improvement
URIs that don't specify a database will now be rejected as invalid.
Contributed by Chris Broome.
## Changes between 3.0.x and 3.1.0 (September 17th, 2016)
### MongoDB Java Driver Update
MongoDB Java driver dependency has been updated to `3.3.0`.
### Cursor Hinting Option Fix
Contributed by Stijn Opheide.
### Improved DBObject to Clojure Map conversion performance
New `from-db-object` implementation for `DBObject` avoids creation of an unnecessary
sequence and instead directly accesses `DBObject` instance in reduce. This should
offer performance improvement of about 20%. A performance test can be found
at [monger.test.stress-test](https://github.com/michaelklishin/monger/blob/master/test/monger/test/stress_test.clj).
Contributed by Juho Teperi.
### Authencation Function No Longer Ignores Credentials
In some cases Monger ignored provided credentials.
Contributed by Artem Chistyakov.
### Macro Type Hint Fixes
Contributed by Andre Ambrosio Boechat.
## Changes between 2.1.0 and 3.0.0
Monger 3.0 is based on the [MongoDB Java driver 3.0](https://www.mongodb.com/blog/post/introducing-30-java-driver)
and has some (relatively minor) **breaking API changes**.
### Error Handling Built Around Write Concerns
Monger no longer provides `monger.core/get-last-error`. It is no
longer needed: write concerns and exceptions is now the primary way for clients
to be notified of operation failures.
### New Authentication API
MongoDB 3.0 supports different authentication mechanisms. Multiple
credentials can be specified for a single connection. The client
and the server then can negotiate what authentication mechanism to use
and which set of credentials succeed.
Monger introduces a new namespace for credential instantiation:
`monger.credentials`. The most common function that relies on
authentication mechanism negotiation is `monger.credentials/for`:
``` clojure
(require '[monger.core :as mg])
(require '[monger.credentials :as mcr])
(let [creds (mcr/for "username" "db-name" "pa$$w0rd")
conn (mg/connect-with-credentials "127.0.0.1" creds)]
)
```
`mg/connect-with-credentials` is the most convenient function to
connect with if you plan on using authentication.
When connecting using a URI, the API hasn't changed.
### monger.search is Gone
`monger.search` is gone. MongoDB 3.0 supports search queries
using regular query operators, namely `$text`. `monger.operators` is
extended to include `$text`, `$search`, `$language`, and `$natural`.
An example of a search query in 3.0:
``` clojure
(require '[monger.core :as mg])
(require '[monger.credentials :as mcr])
(require '[monger.collection :as mc])
(require '[monger.operators :refer [$text $search]])
(let [creds (mcr/for "username" "db-name" "pa$$w0rd")
conn (mg/connect-with-credentials "127.0.0.1" creds)
db (mg/get-db conn "db-name")]
(mc/find-maps db "collection" {$text {$search "hello"}}))
```
### Add allow-disk-use and Cursor Options to Aggregates
`monger.collection/aggregate` now supports `:cursor` and `:allow-disk-use` options.
Contributed by Bartek Marcinowski.
### JSON Serialization of BSON Timestamps
JSON serialisation extensions now support BSON timestamps.
Contributed by Tom McMillen.
## Changes between 2.0.0 and 2.1.0
### Clojure 1.7 Compatibility
Monger now compiles with Clojure 1.7.
### MongoDB Java Driver Update
MongoDB Java driver dependency has been updated to `2.13.x`.
### $each Operator
The `$each` operator now can be used via `monger.operators`.
Contributed by Juha Jokimäki.
## Changes between 1.8.0 and 2.0.0
`2.0` is a major release that has **breaking public API changes**.
### Explicit Connection/DB/GridFS Argument
In Monger 2.0, all key public API functions require an explicit
DB/connection/GridFS object to be provided instead of relying on
a shared dynamic var. This makes Monger much easier to use with
systems such as Component and Jig, as well as concurrent
applications that need to work with multiple connections, database,
or GridFS filesystems.
In other words, instead of
``` clojure
(require '[monger.collection :as mc])
(mc/insert "libraries" {:name "Monger"})
```
it is now necessary to do
``` clojure
(require '[monger.collection :as mc])
(mc/insert db "libraries" {:name "Monger"})
```
This also means that `monger.core/connect!` and
`monger.core/connect-via-uri!` were removed, as was
`monger.multi` namespaces.
To connect to MongoDB, use `monger.core/connect`:
``` clojure
(require '[monger.core :as mg])
(let [conn (mg/connect)])
```
or `monger.core/connect-via-uri`:
``` clojure
(require '[monger.core :as mg])
(let [{:keys [conn db]} (mg/connect-via-uri "mongodb://clojurewerkz/monger:monger@127.0.0.1/monger-test4")])
```
To get a database reference, use `monger.core/get-db`, which now requires a connection
object:
``` clojure
(require '[monger.core :as mg])
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")])
```
### Options as Maps
Functions that take options now require a proper Clojure map instead of
pseudo keyword arguments:
``` clojure
# in Monger 1.x
(mc/update db coll {} {:score 0} :multi true)
# in Monger 2.x
(mc/update db coll {} {:score 0} {:multi true})
```
## Changes between 1.8.0-beta2 and 1.8.0
### Clojure 1.6
Monger now depends on `org.clojure/clojure` version `1.6.0`. It is
still compatible with Clojure 1.4 and if your `project.clj` depends on
a different version, it will be used, but 1.6 is the default now.
## Changes between 1.8.0-beta1 and 1.8.0-beta2
### monger.result Use with WriteConcerns is Deprecated
MongoDB Java driver 2.12.x [no longer guarantees connection affinity](https://github.com/mongodb/mongo-java-driver/releases/tag/r2.12.0-rc0) for thread pool
threads.
This means that `WriteConcern#getLastError` is no longer a safe from concurrency
hazards. Therefore the use of `monger.result` functions on `WriteConcern` instances
is now **deprecated** in MongoDB Java client and Monger.
### MongoDB Java Driver Update
MongoDB Java driver dependency has been [updated to 2.12.x](https://github.com/mongodb/mongo-java-driver/releases/tag/r2.12.0-rc0).
### Default WriteConcern Change
Monger now uses [`WriteConcern/ACKNOWLEDGED`](http://api.mongodb.org/java/2.12/com/mongodb/WriteConcern.html#ACKNOWLEDGED) by default. Functionality-wise
it is the same as `WriteConcern/SAFE` in earlier versions.
## Changes between 1.7.0 and 1.8.0-beta1
### monger.core/connect-via-uri
`monger.core/connect-via-uri` is a version of `monger.core/connect-via-uri!`
which returns the connection instead of mutating a var.
It should be used by projects that are built from reloadable
components, together with `monger.multi.*`.
## Changes between 1.7.0-beta1 and 1.7.0
### MongoDB Java Driver Update
MongoDB Java driver dependency has been [updated to 2.11.3](https://github.com/mongodb/mongo-java-driver/releases/tag/r2.11.3).
### Ragtime Dependency Dropped
Ragtime is now an optional dependency: if your project uses `monger.ragtime`, you
need to add Ragtime to your own `project.clj`:
``` clojure
[ragtime/ragtime.core "0.3.4"]
```
### Validateur Dependency Dropped
[Validateur](http://clojurevalidations.info) is no longer a dependency.
## Changes between 1.6.0 and 1.7.0-beta1
### Fune Tuning Cursor Options
`monger.query` DSL now provides a way to fine tune database cursor
options:
``` clojure
(with-collection "products"
...
(options {:notimeout true, :slaveok false}) ;; where keyword matches Bytes/QUERYOPTION_*
(options [:notimeout :slaveok])
(options com.mongodb.Bytes/QUERYOPTION_NOTIMEOUT) ;; support Java constants
(options :notimeout)
...
```
`monger.cursor` is a new namespace that provides the plumbing for cursor
fine tuning but should not be widely used directly.
### Joda Time Integration Improvements: LocalDate
`LocalDate` instance serialization is now supported
by Monger Joda Time integration.
Contributed by Timo Sulg.
### Clojure 1.3 Is No Longer Supported
Monger now officially supports Clojure 1.4+.
### Cheshire Upgrade
[Cheshire](https://github.com/dakrone/cheshire) dependency has been upgraded to 5.2.0
### ClojureWerkz Support Upgrade
ClojureWerkz Support dependency has been updated to `0.19.0`.
### Validateur 1.5.0
[Validateur](https://github.com/michaelklishin/validateur) dependency has been upgraded to 1.5.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.
Erik Bakstad contributed most of this work.
### MongoDB Java Driver Update
MongoDB Java driver dependency has been [updated to 2.11.2](https://github.com/mongodb/mongo-java-driver/wiki/Release-Notes).
### 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`
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"))
```
### Ragtime changes
Bug fix: `monger.ragtime/applied-migration-ids` now returns a vector (instead of a set) in order to preserve the original creation order of the migrations.
Ragtime dependency has been updated to 0.3.3.
## Changes between 1.4.0 and 1.5.0
### Full Text Search Support
Full text search in MongoDB 2.4 can be used via commands but Monger 1.5 also provides
convenience functions in the `monger.search` namespace:
* `monger.search/search` for performing queries
* `monger.search/results-from` for obtaining hit documents sorted by score
``` clojure
(require '[monger.collection :as mc])
(require '[monger.search :as ms])
(mc/ensure-index coll {:subject "text" :content "text"})
(mc/insert coll {:subject "hello there" :content "this should be searchable"})
(mc/insert coll {:subject "untitled" :content "this is just noize"})
(println (ms/results-from (ms/search coll "hello"))
```
### MongoDB Java Driver Update
MongoDB Java driver dependency has been [updated to 2.11.0](https://github.com/mongodb/mongo-java-driver/wiki/Release-Notes).
### New Geospatial Operators
`monger.operators` now defines a few more operators for convenience:
* `$getWithin`
* `$getIntersects`
* `$near`
Of course, these and any other new operators can be passed as strings (e.g. `"$near"`)
as well.
### monger.core/admin-db
`monger.core/admin-db` is a new convenience function that returns the `admin` database
reference.
### monger.command/admin-command
`monger.command/admin-command` is a new convenience function for running commands
on the `admin` database.
### monger.core/mongo-options Updates
`monger.core/mongo-options` options are now up-to-date with the most recent
MongoDB Java driver.
### Factory DSL Is Gone
Monger's factory DSL (an undocumented experimental feature) has been removed from `monger.testkit`. It did
not work as well as we expected and there are better alternatives available now.
### Clojure 1.5 By Default
Monger now depends on `org.clojure/clojure` version `1.5.1`. It is still compatible with Clojure 1.3+ and if your `project.clj` depends
on a different version, it will be used, but 1.5 is the default now.
We encourage all users to upgrade to 1.5, it is a drop-in replacement for the majority of projects out there.
### Authentication On Default Database
`monger.core/authenticate` now has a 2-arity version that will authenticate
on the default database:
``` clojure
(let [username "myservice"
pwd "LGo5h#B`cTRQ>28tba6u"]
(monger.core/use-db! "mydb")
;; authenticates requests for mydb
(monger.core/authenticate username (.toCharArray pwd)))
```
### ClojureWerkz Support Upgrade
ClojureWerkz Support dependency has been updated to version `0.15.0`.
This means Monger now will use Cheshire `5.0.x`.
### Explicit DBCursor Closure by monger.collection/find-maps and the like
`monger.collection/find-maps` and the like will now explicitly close DB cursors.
GH issue: 47
## Changes between 1.3.0 and 1.4.0
### Cheshire Upgrade
`clojurewerkz.support.json` now requires [Cheshire] `5.0`. There were some incompatible changes
in Cheshire `5.0`, see [Cheshire change log](https://github.com/dakrone/cheshire/blob/master/ChangeLog.md#changes-between-cheshire-500-and-40x).
### data.json Dependency Fixes
`monger.json` no longer requires `data.json` to be present at compile time.
### MongoDB Java Driver Update
MongoDB Java driver dependency has been updated to 2.10.0.
### ClojureWerkz Support Upgrade
ClojureWerkz Support dependency has been updated to version `0.9.0`.
## Changes between 1.2.0 and 1.3.0
### monger.core/disconnect!
`monger.core/disconnect!` closes the default database connection.
### Ragtime 0.3.0
Ragtime dependency has been updated to 0.3.0.
### MongoDB Java Driver Update
MongoDB Java driver dependency has been updated to 2.9.2.
### Cheshire Support
`monger.json` and `monger.joda-time` will now use [Cheshire](https://github.com/dakrone/cheshire) if it is available. [clojure.data.json](https://github.com/clojure/data.json)
is no longer a hard dependency (but still supported if available).
Because `clojure.data.json` is no longer a hard Monger dependency, you need to either add it as explicit
dependency to your project or switch to Cheshire.
To switch to Cheshire (you may need to update your code that uses `clojure.data.json` directly!),
add the following to your `:dependencies` list:
``` clojure
[cheshire "4.0.3"]
```
For `clojure.data.json` version `0.1.2.`:
``` clojure
[org.clojure/data.json "0.2.0"]
```
### ClojureWerkz Support 0.7.0
ClojureWerkz Support dependency has been updated to version `0.7.0`.
No changes yet.
## Changes between 1.1.0 and 1.2.0
@ -582,7 +1139,7 @@ If you need to use `keywordize`, use 4-arity:
### Query DSL has a way to specify if fields need to be keywordized
It is now possible to opt-out of field keywordization in the query DSL:
``` clojure
(with-collection coll
(find {})
@ -608,7 +1165,7 @@ monger.collection/find-map-by-id no longer ignore fields argument. Contributed b
### Meet monger.db and monger.command
`monger.db` namespace was added to perform operations like adding users or dropping databases. Several functions from
`monger.core` will eventually be moved there, but not for 1.0.
`monger.core` will eventually be moved there, but not for 1.0.
`monger.command` namespace includes convenience methods for issuing MongoDB commands.
@ -624,4 +1181,3 @@ given ObjectId. `monger.collection/remove-by-id` is its counterpart for removing
### monger.core/get-db-names
monger.core/get-db-names returns a set of databases. Contributed by Toby Hede.

100
README.md
View file

@ -1,45 +1,43 @@
# Monger, a modern Clojure MongoDB Driver
[![Build Status](https://travis-ci.org/xingzhefeng/monger.svg?branch=master)](https://travis-ci.org/xingzhefeng/monger)
Monger is an idiomatic [Clojure MongoDB driver](http://clojuremongodb.info) for a more civilized age.
It has batteries included, offers powerful expressive query DSL, strives to support every MongoDB 2.0+ feature and has sane defaults. Monger is built from the
ground up for Clojure 1.3+ and sits on top of the official MongoDB Java driver.
It has batteries included, offers powerful expressive query DSL,
strives to support modern MongoDB features and have the "look and feel" and
flexibility of the MongoDB shell.
Monger is built from for modern Clojure versions and sits on top of
the official MongoDB Java driver.
## Project Goals
There is one MongoDB client for Clojure that has been around since 2009. So, why create another one? Monger authors
wanted a client that will
wanted a client that would
* Support most of MongoDB 2.0+ features, focus on those that really matter.
* Support most of modern MongoDB features, focus on those that really matter.
* Be [well documented](http://clojuremongodb.info).
* Be [well tested](https://github.com/michaelklishin/monger/tree/master/test/monger/test).
* Target Clojure 1.3.0 and later from the ground up.
* Target modern Clojure versions.
* Be as close to the Mongo shell query language as practical
* Integrate with libraries like clojure.data.json, Joda Time, [Ragtime](https://github.com/weavejester/ragtime).
* Integrate with libraries like Joda Time, [Cheshire](https://github.com/dakrone/cheshire), clojure.data.json, [Ragtime](https://github.com/weavejester/ragtime).
* Support URI connections to be friendly to Heroku and other PaaS providers.
* Not carry technical debt from 2009 forever.
* Integrate usage of JavaScript files and ClojureScript (as soon as the compiler gets artifact it is possible to depend on for easy embedding).
## Community
[Monger has a mailing list](https://groups.google.com/forum/#!forum/clojure-mongodb). Feel free to join it and ask any questions you may have.
To subscribe for announcements of releases, important changes and so on, please follow [@ClojureWerkz](https://twitter.com/#!/clojurewerkz) on Twitter.
## Project Maturity
Monger is not a young project: started in July 2011, it is over 1 year old with active production use from week 1.
Monger is not a young project: started in July 2011, it is over 7
years old with active production use from week 1.
## Artifacts
Monger artifacts are [released to Clojars](https://clojars.org/com.novemberain/monger). If you are using Maven, add the following repository
definition to your `pom.xml`:
Monger artifacts are [released to
Clojars](https://clojars.org/com.novemberain/monger). If you are using
Maven, add the following repository definition to your `pom.xml`:
``` xml
<repository>
@ -52,68 +50,60 @@ definition to your `pom.xml`:
With Leiningen:
[com.novemberain/monger "1.2.0"]
[com.novemberain/monger "3.5.0"]
With Maven:
<dependency>
<groupId>com.novemberain</groupId>
<artifactId>monger</artifactId>
<version>1.2.0</version>
<version>3.5.0</version>
</dependency>
## Getting Started
Please refer to our [Getting Started guide](http://clojuremongodb.info/articles/getting_started.html). Don't hesitate to join our [mailing list](https://groups.google.com/forum/#!forum/clojure-mongodb) and ask questions, too!
Please refer to our [Getting Started
guide](http://clojuremongodb.info/articles/getting_started.html). Don't
hesitate to join our [mailing
list](https://groups.google.com/forum/#!forum/clojure-mongodb) and ask
questions, too!
## Documentation & Examples
Please see our [documentation guides site](http://clojuremongodb.info/) and [API reference](http://reference.clojuremongodb.info).
Our [test suite](https://github.com/michaelklishin/monger/tree/master/test/monger/test) also has many code examples.
Our [test suite](https://github.com/michaelklishin/monger/tree/master/test/monger/test)
also has many code examples.
## Community
[Monger has a mailing list](https://groups.google.com/forum/#!forum/clojure-mongodb). Feel
free to join it and ask any questions you may have.
To subscribe for announcements of releases, important changes and so
on, please follow [@ClojureWerkz](https://twitter.com/#!/clojurewerkz)
on Twitter.
## Supported Clojure versions
Monger is built from the ground up for Clojure 1.3 and up. Clojure 1.4 is recommended.
Monger requires Clojure 1.8+. The most recent
stable release is highly recommended.
## Continuous Integration Status
[![Continuous Integration status](https://secure.travis-ci.org/michaelklishin/monger.png)](http://travis-ci.org/michaelklishin/monger)
[![Continuous Integration status](https://secure.travis-ci.org/michaelklishin/monger.svg)](http://travis-ci.org/michaelklishin/monger)
## Monger Is a ClojureWerkz Project
Monger is part of the [group of Clojure libraries known as ClojureWerkz](http://clojurewerkz.org), together with
[Neocons](https://github.com/michaelklishin/neocons), [Langohr](https://github.com/michaelklishin/langohr), [Elastisch](https://github.com/clojurewerkz/elastisch), [Welle](https://github.com/michaelklishin/welle), [Quartzite](https://github.com/michaelklishin/quartzite) and several others.
## Write Performance
Monger insert operations are efficient and have very little overhead compared to the underlying Java driver. Here
are some numbers on a MacBook Pro from fall 2010 with Core i7 and an Intel SSD drive:
```
Testing monger.test.stress
Inserting 1000 documents...
"Elapsed time: 25.699 msecs"
Inserting 10000 documents...
"Elapsed time: 135.069 msecs"
Inserting 100000 documents...
"Elapsed time: 515.969 msecs"
```
With the `SAFE` write concern, it takes roughly 0.5 second to insert 100,000 documents with Clojure 1.3.0.
[Cassaforte](http://clojurecassandra.info), [Langohr](http://clojurerabbitmq.info), [Elastisch](http://clojureelasticsearch.info), [Quartzite](http://clojurequartz.info) and several others.
@ -122,7 +112,14 @@ With the `SAFE` write concern, it takes roughly 0.5 second to insert 100,000 doc
Monger uses [Leiningen 2](https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md). Make sure you have it installed and then run tests against
supported Clojure versions using
lein2 all test
./bin/ci/before_script.sh
lein all do clean, javac, test
Or, if you don't have mongodb installed, you can use docker
docker-compose up
./bin/ci/before_script_docker.sh
lein all do clean, javac, test
Then create a branch and make your changes on it. Once you are done with your changes and all tests pass, submit a pull request
on Github.
@ -131,6 +128,7 @@ on Github.
## License
Copyright (C) 2011-2012 Michael S. Klishin
Copyright (C) 2011-2018 [Michael S. Klishin](http://twitter.com/michaelklishin), Alex Petrov, and the ClojureWerkz team.
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).

View file

@ -1,8 +1,18 @@
#!/bin/sh
# Check which MongoDB shell is available
if command -v mongosh >/dev/null 2>&1; then
MONGO_SHELL="mongosh"
elif command -v mongo >/dev/null 2>&1; then
MONGO_SHELL="mongo"
else
echo "Error: Neither mongo nor mongosh shell found. Please install MongoDB shell."
exit 1
fi
# MongoDB Java driver won't run authentication twice on the same DB instance,
# so we need to use multiple DBs.
mongo --eval 'db.addUser("clojurewerkz/monger", "monger")' monger-test
mongo --eval 'db.addUser("clojurewerkz/monger", "monger")' monger-test2
mongo --eval 'db.addUser("clojurewerkz/monger", "monger")' monger-test3
mongo --eval 'db.addUser("clojurewerkz/monger", "monger")' monger-test4
$MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test
$MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test2
$MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test3
$MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test4

18
bin/ci/before_script_docker.sh Executable file
View file

@ -0,0 +1,18 @@
#!/bin/sh
# Check which MongoDB shell is available in the container
if docker exec mongo_test which mongosh >/dev/null 2>&1; then
MONGO_SHELL="mongosh"
elif docker exec mongo_test which mongo >/dev/null 2>&1; then
MONGO_SHELL="mongo"
else
echo "Error: Neither mongo nor mongosh shell found in the container."
exit 1
fi
# MongoDB Java driver won't run authentication twice on the same DB instance,
# so we need to use multiple DBs.
docker exec mongo_test $MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test
docker exec mongo_test $MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test2
docker exec mongo_test $MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test3
docker exec mongo_test $MONGO_SHELL --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], mechanisms: ["SCRAM-SHA-1"], passwordDigestor: "client"})' monger-test4

View file

@ -0,0 +1,11 @@
#!/bin/sh
# MongoDB seems to need some time to boot first. MK.
sleep 5
# MongoDB Java driver won't run authentication twice on the same DB instance,
# so we need to use multiple DBs.
mongo --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], passwordDigestor: "client"})' monger-test
mongo --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], passwordDigestor: "client"})' monger-test2
mongo --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], passwordDigestor: "client"})' monger-test3
mongo --eval 'db.createUser({"user": "clojurewerkz/monger", "pwd": "monger", roles: ["dbAdmin"], passwordDigestor: "client"})' monger-test4

8
bin/ci/install_mongodb.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org

11
docker-compose.yml Normal file
View file

@ -0,0 +1,11 @@
# Use root/example as user/password credentials
version: '3.1'
services:
mongo:
image: mongo
container_name: mongo_test
restart: always
ports:
- "27017:27017"

View file

@ -1,61 +1,58 @@
(defproject com.novemberain/monger "1.2.1-SNAPSHOT"
(defproject com.novemberain/monger "4.0.0-SNAPSHOT"
:description "Monger is a Clojure MongoDB client for a more civilized age: friendly, flexible and with batteries included"
:url "http://clojuremongodb.info"
:min-lein-version "2.0.0"
:license {:name "Eclipse Public License"}
:dependencies [[org.clojure/clojure "1.4.0"]
[org.mongodb/mongo-java-driver "2.9.0"]
[com.novemberain/validateur "1.2.0"]
[clojurewerkz/support "0.6.0"]
[ragtime/ragtime.core "0.2.0"]]
:min-lein-version "2.5.1"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.11.1"]
[org.mongodb/mongodb-driver "3.12.11"]
[clojurewerkz/support "1.5.0"]]
:test-selectors {:default (fn [m]
(and (not (:performance m))
(not (:edge-features m))
(not (:time-consuming m))))
:focus :focus
:updating :updating
:indexing :indexing
:external :external
:cache :cache
:gridfs :gridfs
:command :command
:performance :performance
:focus :focus
:authentication :authentication
:updating :updating
:indexing :indexing
:external :external
:cache :cache
:gridfs :gridfs
:command :command
:integration :integration
:performance :performance
;; as in, edge mongodb server
:edge-features :edge-features
:time-consuming :time-consuming
:all (constantly true)}
:source-paths ["src/clojure"]
:java-source-paths ["src/java"]
:javac-options ["-target" "1.6" "-source" "1.6"]
:codox {:exclude [monger.internal.pagination
monger.internal.fn
;; these are not fully baked yet or have changes
;; that are not entirely backwards compatible with 1.0. MK.
monger.testkit
monger.ring.session-store]}
:javac-options ["-target" "1.8" "-source" "1.8"]
:mailing-list {:name "clojure-mongodb"
:archive "https://groups.google.com/group/clojure-mongodb"
:post "clojure-mongodb@googlegroups.com"}
:profiles {:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]}
:1.5 {:dependencies [[org.clojure/clojure "1.5.0-master-SNAPSHOT"]]}
:profiles {:1.10 {:dependencies [[org.clojure/clojure "1.10.2"]]}
:1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}
:dev {:resource-paths ["test/resources"]
:dependencies [[clj-time "0.4.2" :exclusions [org.clojure/clojure]]
[org.clojure/data.json "0.1.2" :exclusions [org.clojure/clojure]]
[org.clojure/tools.cli "0.2.1" :exclusions [org.clojure/clojure]]
[org.clojure/core.cache "0.6.0" :exclusions [org.clojure/clojure]]
[ring/ring-core "1.1.0"]]
:plugins [[codox "0.6.1"]]
:codox {:sources ["src/clojure"]
:output-dir "doc/api"}}
:dependencies [[clj-time "0.15.1" :exclusions [org.clojure/clojure]]
[cheshire "5.8.1" :exclusions [org.clojure/clojure]]
[org.clojure/data.json "2.5.0" :exclusions [org.clojure/clojure]]
[org.clojure/tools.cli "0.4.1" :exclusions [org.clojure/clojure]]
[org.clojure/core.cache "0.7.1" :exclusions [org.clojure/clojure]]
[ring/ring-core "1.7.1" :exclusions [org.clojure/clojure]]
[com.novemberain/validateur "2.6.0" :exclusions [org.clojure/clojure]]
[ch.qos.logback/logback-classic "1.2.3" :exclusions [org.slf4j/slf4j-api]]
[ragtime/core "0.7.2" :exclusions [org.clojure/clojure]]]
:plugins [[lein-codox "0.10.5"]]
:codox {:source-paths ["src/clojure"]
:namespaces [#"^monger\.(?!internal)"]}}
;; only clj-time/JodaTime available, used to test monger.joda-time w/o clojure.data.json
:dev2 {:resource-paths ["test/resources"]
:dependencies [[clj-time "0.4.2" :exclusions [org.clojure/clojure]]]}}
:aliases {"all" ["with-profile" "dev:dev,1.3:dev,1.5"]
"ci" ["with-profile" "dev:dev,1.3:dev,1.5"]}
:repositories {"sonatype" {:url "http://oss.sonatype.org/content/repositories/releases"
:dependencies [[clj-time "0.15.2" :exclusions [org.clojure/clojure]]]}}
:aliases {"all" ["with-profile" "dev:dev,1.10:dev,1.9:dev"]}
:repositories {"sonatype" {:url "https://oss.sonatype.org/content/repositories/releases"
:snapshots false
:releases {:checksum :fail :update :always}}
"sonatype-snapshots" {:url "http://oss.sonatype.org/content/repositories/snapshots"
"sonatype-snapshots" {:url "https://oss.sonatype.org/content/repositories/snapshots"
:snapshots true
:releases {:checksum :fail :update :always}}}
:aot [monger.conversion])
:releases {:checksum :fail :update :always}}})

View file

@ -1,12 +1,46 @@
(ns ^{:doc "clojure.core.cache implementation(s) on top of MongoDB.
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.cache
"clojure.core.cache implementation(s) on top of MongoDB.
Related documentation guide: http://clojuremongodb.info/articles/integration.html"
:author "Michael S. Klishin"}
monger.cache
(:require [monger.collection :as mc]
[clojure.core.cache :as cache])
(:use monger.conversion)
(:import clojure.core.cache.CacheProtocol))
Related documentation guide: http://clojuremongodb.info/articles/integration.html"
(:require [monger.collection :as mc :refer [find-one find-by-id find-map-by-id]]
[clojure.core.cache :as cache]
[monger.conversion :as cnv])
(:import clojure.core.cache.CacheProtocol
[com.mongodb DB DBObject WriteConcern]
java.util.Map))
;;
;; Implementation
@ -19,36 +53,33 @@
;; API
;;
(defrecord BasicMongerCache [collection])
(defrecord BasicMongerCache [db collection])
(extend-protocol cache/CacheProtocol
BasicMongerCache
(lookup [c k]
(:value (mc/find-map-by-id (:collection c) k)))
#_ (lookup [c k not-found]
(if-let [doc (mc/find-map-by-id (:collection c) k)]
(:value doc)
not-found))
(let [m (mc/find-map-by-id (:db c) (:collection c) k)]
(:value m)))
(has? [c k]
(not (nil? (mc/find-by-id (get c :collection) k))))
(not (nil? (mc/find-by-id (:db c) (:collection c) k))))
(hit [this k]
this)
(miss [c k v]
(mc/insert (get c :collection) {:_id k :value v})
(mc/insert (:db c) (:collection c) {:_id k :value v})
c)
(evict [c k]
(mc/remove-by-id (get c :collection) k)
(mc/remove-by-id (:db c) (:collection c) k)
c)
(seed [c m]
(mc/insert-batch (get c :collection) (map (fn [[k v]]
{:_id k :value v}) m))
(mc/insert-batch (:db c) (:collection c) (map (fn [[k v]]
{:_id k :value v}) m))
c))
(defn basic-monger-cache-factory
([]
(BasicMongerCache. default-cache-collection))
([collection]
(BasicMongerCache. collection))
([collection base]
(cache/seed (BasicMongerCache. collection) base)))
([^DB db]
(BasicMongerCache. db default-cache-collection))
([^DB db collection]
(BasicMongerCache. db collection))
([^DB db collection base]
(cache/seed (BasicMongerCache. db collection) base)))

View file

@ -1,44 +1,68 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;; Copyright (c) 2012 Toby Hede
;; Copyright (c) 2012 Baishampayan Ghose
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; Copyright (c) 2012 Toby Hede
;; Copyright (c) 2012 Baishampayan Ghose
;;
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(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
(:refer-clojure :exclude [find remove count drop distinct empty?])
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor MapReduceCommand MapReduceCommand$OutputType]
* 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? any? update])
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern
DBCursor MapReduceCommand MapReduceCommand$OutputType AggregationOutput
AggregationOptions AggregationOptions$OutputMode]
[java.util List Map]
[java.util.concurrent TimeUnit]
[clojure.lang IPersistentMap ISeq]
org.bson.types.ObjectId)
(:require [monger core result])
(:use [monger.conversion]))
;;
;; Implementation
;;
(definline check-not-nil!
[ref ^String message]
`(when (nil? ~ref)
(throw (IllegalArgumentException. ~message))))
(:require [monger.core :as mc]
[monger.result :as mres]
[monger.conversion :refer :all]
[monger.constraints :refer :all]
[monger.util :refer [into-array-list]]))
;;
@ -50,28 +74,17 @@
;;
(defn ^WriteResult insert
"Saves @document@ to @collection@ and returns write result monger.result/ok? and similar functions operate on. You can optionally specify WriteConcern.
"Saves document to collection and returns a write result monger.result/acknowledged?
and related functions operate on. You can optionally specify a WriteConcern.
In case you need the exact inserted document returned, with the :_id key generated, use monger.collection/insert-and-return
instead.
EXAMPLES:
;; returns write result
(monger.collection/insert \"people\" {:name \"Joe\", :age 30})
(monger.collection/insert \"people\" {:name \"Joe\", :age 30, WriteConcern/SAFE})
"
([^String collection document]
(.insert (.getCollection monger.core/*mongodb-database* (name collection))
In case you need the exact inserted document returned, with the :_id key generated,
use monger.collection/insert-and-return instead."
([^DB db ^String coll document]
(.insert (.getCollection db (name coll))
(to-db-object document)
^WriteConcern monger.core/*mongodb-write-concern*))
([^String collection document ^WriteConcern concern]
(.insert (.getCollection monger.core/*mongodb-database* (name collection))
(to-db-object document)
concern))
([^DB db ^String collection document ^WriteConcern concern]
(.insert (.getCollection db (name collection))
^WriteConcern mc/*mongodb-write-concern*))
([^DB db ^String coll document ^WriteConcern concern]
(.insert (.getCollection db (name coll))
(to-db-object document)
concern)))
@ -79,49 +92,30 @@
(defn ^clojure.lang.IPersistentMap insert-and-return
"Like monger.collection/insert but returns the inserted document as a persistent Clojure map.
If the :_id key wasn't set on the document, it will be generated and merged into the returned map.
EXAMPLES:
;; returns the entire document with :_id generated
(monger.collection/insert-and-return \"people\" {:name \"Joe\", :age 30})
(monger.collection/insert-and-return \"people\" {:name \"Joe\", :age 30, WriteConcern/SAFE})
"
([^String collection document]
(insert-and-return ^DB monger.core/*mongodb-database* collection document ^WriteConcern monger.core/*mongodb-write-concern*))
([^String collection document ^WriteConcern concern]
(insert-and-return ^DB monger.core/*mongodb-database* collection document concern))
([^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.
If the :_id key wasn't set on the document, it will be generated and merged into the returned
map."
([^DB db ^String coll document]
(insert-and-return db coll document ^WriteConcern mc/*mongodb-write-concern*))
([^DB db ^String coll 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)
(insert db coll doc concern)
doc)))
(defn ^WriteResult insert-batch
"Saves @documents@ do @collection@. You can optionally specify WriteConcern as a third argument.
EXAMPLES:
(monger.collection/insert-batch \"people\" [{:name \"Joe\", :age 30}, {:name \"Paul\", :age 27}])
(monger.collection/insert-batch \"people\" [{:name \"Joe\", :age 30}, {:name \"Paul\", :age 27}] WriteConcern/NORMAL)
"
([^String collection ^List documents]
(.insert (.getCollection monger.core/*mongodb-database* (name collection))
"Saves documents to collection. You can optionally specify WriteConcern as a third argument."
([^DB db ^String coll ^List documents]
(.insert (.getCollection db (name coll))
^List (to-db-object documents)
^WriteConcern monger.core/*mongodb-write-concern*))
([^String collection ^List documents ^WriteConcern concern]
(.insert (.getCollection monger.core/*mongodb-database* (name collection))
^List (to-db-object documents)
concern))
([^DB db ^String collection ^List documents ^WriteConcern concern]
(.insert (.getCollection db (name collection))
^WriteConcern mc/*mongodb-write-concern*))
([^DB db ^String coll ^List documents ^WriteConcern concern]
(.insert (.getCollection db (name coll))
^List (to-db-object documents)
concern)))
@ -132,126 +126,83 @@
(defn ^DBCursor find
"Queries for objects in this collection.
This function returns DBCursor, which allows you to iterate over DBObjects.
If you want to manipulate clojure sequences maps, please @find-maps@.
EXAMPLES:
;; return all objects in this collection.
(mgcol/find \"people\")
;; return all objects matching query
(mgcol/find \"people\" {:company \"Comp Corp\"})
;; return all objects matching query, taking only specified fields
(mgcol/find \"people\" {:company \"Comp Corp\"} [:first_name :last_name])
"
([^String collection]
(.find (.getCollection monger.core/*mongodb-database* (name collection))))
([^String collection ^Map ref]
(.find (.getCollection monger.core/*mongodb-database* (name collection))
If you want to manipulate clojure sequences maps, use find-maps."
([^DB db ^String coll]
(.find (.getCollection db (name coll))))
([^DB db ^String coll ^Map ref]
(.find (.getCollection db (name coll))
(to-db-object ref)))
([^String collection ^Map ref fields]
(.find (.getCollection monger.core/*mongodb-database* (name collection))
(to-db-object ref)
(as-field-selector fields)))
([^DB db ^String collection ^Map ref fields]
(.find (.getCollection db (name collection))
([^DB db ^String coll ^Map ref fields]
(.find (.getCollection db (name coll))
(to-db-object ref)
(as-field-selector fields))))
(defn find-maps
"Queries for objects in this collection.
This function returns clojure Seq of Maps.
If you want to work directly with DBObject, use find.
"
([^String collection]
(map (fn [x] (from-db-object x true)) (find collection)))
([^String collection ^Map ref]
(map (fn [x] (from-db-object x true)) (find collection ref)))
([^String collection ^Map ref fields]
(map (fn [x] (from-db-object x true)) (find collection ref fields)))
([^DB db ^String collection ^Map ref fields]
(map (fn [x] (from-db-object x true)) (find db collection ref fields))))
If you want to work directly with DBObject, use find."
([^DB db ^String coll]
(with-open [dbc (find db coll)]
(map (fn [x] (from-db-object x true)) dbc)))
([^DB db ^String coll ^Map ref]
(with-open [dbc (find db coll ref)]
(map (fn [x] (from-db-object x true)) dbc)))
([^DB db ^String coll ^Map ref fields]
(find-maps db coll ref fields true))
([^DB db ^String coll ^Map ref fields keywordize]
(with-open [dbc (find db coll ref fields)]
(map (fn [x] (from-db-object x keywordize)) dbc))))
(defn find-seq
"Queries for objects in this collection, returns ISeq of DBObjects."
([^String collection]
(seq (find collection)))
([^String collection ^Map ref]
(seq (find collection ref)))
([^String collection ^Map ref fields]
(seq (find collection ref fields)))
([^DB db ^String collection ^Map ref fields]
(seq (find db collection ref fields))))
([^DB db ^String coll]
(with-open [dbc (find db coll)]
(seq dbc)))
([^DB db ^String coll ^Map ref]
(with-open [dbc (find db coll ref)]
(seq dbc)))
([^DB db ^String coll ^Map ref fields]
(with-open [dbc (find db coll ref fields)]
(seq dbc))))
;;
;; monger.collection/find-one
;;
(defn ^DBObject find-one
"Returns a single DBObject from this collection matching the query.
EXAMPLES:
(mgcol/find-one collection {:language \"Clojure\"})
;; Return only :language field.
;; Note that _id field is always returned.
(mgcol/find-one collection {:language \"Clojure\"} [:language])
"
([^String collection ^Map ref]
(.findOne (.getCollection monger.core/*mongodb-database* (name collection))
"Returns a single DBObject from this collection matching the query."
([^DB db ^String coll ^Map ref]
(.findOne (.getCollection db (name coll))
(to-db-object ref)))
([^String collection ^Map ref fields]
(.findOne (.getCollection monger.core/*mongodb-database* (name collection))
(to-db-object ref)
^DBObject (as-field-selector fields)))
([^DB db ^String collection ^Map ref fields]
(.findOne (.getCollection db (name collection))
([^DB db ^String coll ^Map ref fields]
(.findOne (.getCollection db (name coll))
(to-db-object ref)
^DBObject (as-field-selector fields))))
(defn ^IPersistentMap find-one-as-map
"Returns a single object converted to Map from this collection matching the query."
([^String collection ^Map ref]
(from-db-object ^DBObject (find-one collection ref) true))
([^String collection ^Map ref fields]
(from-db-object ^DBObject (find-one collection ref fields) true))
([^String collection ^Map ref fields keywordize]
(from-db-object ^DBObject (find-one collection ref fields) keywordize)))
([^DB db ^String coll ^Map ref]
(from-db-object ^DBObject (find-one db coll ref) true))
([^DB db ^String coll ^Map ref fields]
(from-db-object ^DBObject (find-one db coll ref fields) true))
([^DB db ^String coll ^Map ref fields keywordize]
(from-db-object ^DBObject (find-one db coll ref fields) keywordize)))
;;
;; monger.collection/find-and-modify
;;
(defn ^DBObject find-and-modify
"Atomically modify a document (at most one) and return it.
EXAMPLES:
;; Find and modify a document
(mgcol/find-and-modify collection {:language \"Python\"} {:language \"Clojure\"})
;; If multiple documents match, choose the first one in the specified order
(mgcol/find-and-modify collection {:language \"Python\"} {:language \"Clojure\"} :sort {:language -1})
;; Remove the object before returning
(mgcol/find-and-modify collection {:language \"Python\"} {} :remove true)
;; Return the modified object instead of the old one
(mgcol/find-and-modify collection {:language \"Python\"} {:language \"Clojure\"} :return-new true)
;; Retrieve a subset of fields
(mgcol/find-and-modify collection {:language \"Python\"} {:language \"Clojure\"} :fields [ :language ])
;; Create the object if it doesn't exist
(mgcol/find-and-modify collection {:language \"Factor\"} {:language \"Clojure\"} :upsert true)
"
([^String collection ^Map conditions ^Map document & {:keys [fields sort remove return-new upsert keywordize] :or
{fields nil sort nil remove false return-new false upsert false keywordize true}}]
(let [coll (.getCollection monger.core/*mongodb-database* (name collection))
(defn ^IPersistentMap find-and-modify
"Atomically modify a document (at most one) and return it."
([^DB db ^String coll ^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 coll))
maybe-fields (when fields (as-field-selector fields))
maybe-sort (when sort (to-db-object sort))]
(from-db-object
@ -263,150 +214,122 @@
;;
(defn ^DBObject find-by-id
"Returns a single object with matching _id field.
EXAMPLES:
(mgcol/find-one-by-id collection (ObjectId. \"4ef45ab4744e9fd632640e2d\"))
;; Return only :language field.
;; Note that _id field is always returned.
(mgcol/find-one-by-id collection (ObjectId. \"4ef45ab4744e9fd632640e2d\") [:language])
"
([^String collection id]
"Returns a single object with matching _id field."
([^DB db ^String coll id]
(check-not-nil! id "id must not be nil")
(find-one collection {:_id id}))
([^String collection id fields]
(find-one db coll {:_id id}))
([^DB db ^String coll id fields]
(check-not-nil! id "id must not be nil")
(find-one collection {:_id id} fields))
([^DB db ^String collection id fields]
(check-not-nil! id "id must not be nil")
(find-one db collection {:_id id} fields)))
(find-one db coll {:_id id} fields)))
(defn ^IPersistentMap find-map-by-id
"Returns a single object, converted to map with matching _id field."
([^String collection id]
([^DB db ^String coll id]
(check-not-nil! id "id must not be nil")
(from-db-object ^DBObject (find-one-as-map collection {:_id id}) true))
([^String collection id fields]
(find-one-as-map db coll {:_id id}))
([^DB db ^String coll id fields]
(check-not-nil! id "id must not be nil")
(from-db-object ^DBObject (find-one-as-map collection {:_id id} fields) true))
([^String collection id fields keywordize]
(find-one-as-map db coll {:_id id} fields))
([^DB db ^String coll id fields keywordize]
(check-not-nil! id "id must not be nil")
(from-db-object ^DBObject (find-one-as-map collection {:_id id} fields) keywordize)))
;;
;; monger.collection/group
;;
;; TBD
(find-one-as-map db coll {:_id id} fields keywordize)))
;;
;; monger.collection/count
;;
(defn count
"Returns the number of documents in this collection.
Takes optional conditions as an argument.
(monger.collection/count collection)
(monger.collection/count collection {:first_name \"Paul\"})"
(^long [^String collection]
(.count (.getCollection monger.core/*mongodb-database* (name collection))))
(^long [^String collection ^Map conditions]
(.count (.getCollection monger.core/*mongodb-database* (name collection)) (to-db-object conditions)))
(^long [^DB db ^String collection ^Map conditions]
(.count (.getCollection db (name collection)) (to-db-object conditions))))
Takes optional conditions as an argument."
(^long [^DB db ^String coll]
(.count (.getCollection db (name coll))))
(^long [^DB db ^String coll ^Map conditions]
(.count (.getCollection db (name coll)) (to-db-object conditions))))
(defn any?
"Wether the collection has any items at all, or items matching query.
EXAMPLES:
;; wether the collection has any items
(mgcol/any? collection)
(mgcol/any? collection {:language \"Clojure\"}))
"
([^String collection]
(> (count collection) 0))
([^String collection ^Map conditions]
(> (count collection conditions) 0))
([^DB db ^String collection ^Map conditions]
(> (count db collection conditions) 0)))
"Whether the collection has any items at all, or items matching query."
([^DB db ^String coll]
(> (count db coll) 0))
([^DB db ^String coll ^Map conditions]
(> (count db coll conditions) 0)))
(defn empty?
"Wether the collection is empty.
EXAMPLES:
(mgcol/empty? \"things\")
"
([^String collection]
(= (count collection) 0))
([^DB db ^String collection]
(= (count db collection {}) 0)))
"Whether the collection is empty."
[^DB db ^String coll]
(= (count db coll {}) 0))
;; monger.collection/update
(defn ^WriteResult update
"Performs an update operation.
Please note that update is potentially destructive operation. It will update your document with the given set
emptying the fields not mentioned in (^Map document). In order to only change certain fields, please use
Please note that update is potentially destructive operation. It updates document with the given set
emptying the fields not mentioned in the new document. In order to only change certain fields, use
\"$set\".
EXAMPLES
(monger.collection/update \"people\" {:first_name \"Raul\"} {\"$set\" {:first_name \"Paul\"}})
You can use all the Mongodb Modifier Operations ($inc, $set, $unset, $push, $pushAll, $addToSet, $pop, $pull
$pullAll, $rename, $bit) here, as well
EXAMPLES
(monger.collection/update \"people\" {:first_name \"Paul\"} {\"$set\" {:index 1}})
(monger.collection/update \"people\" {:first_name \"Paul\"} {\"$inc\" {:index 5}})
(monger.collection/update \"people\" {:first_name \"Paul\"} {\"$unset\" {:years_on_stage 1}})
It also takes modifiers, such as :upsert and :multi.
EXAMPLES
;; add :band field to all the records found in \"people\" collection, otherwise only the first matched record
;; will be updated
(monger.collection/update \"people\" {} {\"$set\" {:band \"The Beatles\"}} :multi true)
;; inserts the record if it did not exist in the collection
(monger.collection/update \"people\" {:first_name \"Yoko\"} {:first_name \"Yoko\" :last_name \"Ono\"} :upsert true)
You can use all the MongoDB modifier operations ($inc, $set, $unset, $push, $pushAll, $addToSet, $pop, $pull
$pullAll, $rename, $bit) here as well.
It also takes options, such as :upsert and :multi.
By default :upsert and :multi are false."
([^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 monger.core/*mongodb-database* (name collection))
([^DB db ^String coll ^Map conditions ^Map document]
(update db coll conditions document {}))
([^DB db ^String coll ^Map conditions ^Map document {:keys [upsert multi write-concern]
:or {upsert false
multi false
write-concern mc/*mongodb-write-concern*}}]
(.update (.getCollection db (name coll))
(to-db-object conditions)
(to-db-object document)
upsert
multi
write-concern)))
(defn ^WriteResult upsert
"Performs an upsert.
This is a convenience function that delegates to monger.collection/update and
sets :upsert to true.
See monger.collection/update documentation"
([^DB db ^String coll ^Map conditions ^Map document]
(upsert db coll conditions document {}))
([^DB db ^String coll ^Map conditions ^Map document {:keys [multi write-concern]
:or {multi false
write-concern mc/*mongodb-write-concern*}}]
(update db coll conditions document {:multi multi :write-concern write-concern :upsert true})))
(defn ^WriteResult update-by-id
"Update a document with given id"
[^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 monger.core/*mongodb-database* (name collection))
(to-db-object {:_id id})
(to-db-object document)
upsert
false
write-concern))
([^DB db ^String coll id ^Map document]
(update-by-id db coll id document {}))
([^DB db ^String coll id ^Map document {:keys [upsert write-concern]
:or {upsert false
write-concern mc/*mongodb-write-concern*}}]
(check-not-nil! id "id must not be nil")
(.update (.getCollection db (name coll))
(to-db-object {:_id id})
(to-db-object document)
upsert
false
write-concern)))
(defn ^WriteResult update-by-ids
"Update documents by given ids"
([^DB db ^String coll ids ^Map document]
(update-by-ids db coll ids document {}))
([^DB db ^String coll ids ^Map document {:keys [upsert write-concern]
:or {upsert false
write-concern mc/*mongodb-write-concern*}}]
(check-not-nil! (seq ids) "ids must not be nil or empty")
(.update (.getCollection db (name coll))
(to-db-object {:_id {"$in" ids}})
(to-db-object document)
upsert
true
write-concern)))
;; monger.collection/save
@ -418,22 +341,13 @@
If the object is already in the database, it will be updated.
This function returns write result. If you want to get the exact persisted document back,
use `save-and-return`.
EXAMPLES
(monger.collection/save \"people\" {:first_name \"Ian\" :last_name \"Gillan\"})
"
([^String collection ^Map document]
(.save (.getCollection monger.core/*mongodb-database* (name collection))
use `save-and-return`."
([^DB db ^String coll ^Map document]
(.save (.getCollection db (name coll))
(to-db-object document)
monger.core/*mongodb-write-concern*))
([^String collection ^Map document ^WriteConcern write-concern]
(.save (.getCollection monger.core/*mongodb-database* (name collection))
(to-db-object document)
write-concern))
([^DB db ^String collection ^Map document ^WriteConcern write-concern]
(.save (.getCollection db (name collection))
mc/*mongodb-write-concern*))
([^DB db ^String coll ^Map document ^WriteConcern write-concern]
(.save (.getCollection db (name coll))
(to-db-object document)
write-concern)))
@ -446,76 +360,51 @@
This function returns the exact persisted document back, including the `:_id` key in
case of an insert.
If you want to get write result back, use `save`.
EXAMPLES
(monger.collection/save-and-return \"people\" {:first_name \"Ian\" :last_name \"Gillan\"})
"
([^String collection ^Map document]
(save-and-return ^DB monger.core/*mongodb-database* collection document ^WriteConcern monger.core/*mongodb-write-concern*))
([^String collection ^Map document ^WriteConcern write-concern]
(save-and-return ^DB monger.core/*mongodb-database* collection document write-concern))
([^DB db ^String collection ^Map document ^WriteConcern write-concern]
If you want to get write result back, use `save`."
([^DB db ^String coll ^Map document]
(save-and-return db coll document ^WriteConcern mc/*mongodb-write-concern*))
([^DB db ^String coll ^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)
(save db coll doc write-concern)
doc)))
;; monger.collection/remove
(defn ^WriteResult remove
"Removes objects from the database.
EXAMPLES
(monger.collection/remove collection) ;; Removes all documents from DB
(monger.collection/remove collection {:language \"Clojure\"}) ;; Removes documents based on given query
"
([^String collection]
(.remove (.getCollection monger.core/*mongodb-database* (name collection)) (to-db-object {})))
([^String collection ^Map conditions]
(.remove (.getCollection monger.core/*mongodb-database* (name collection)) (to-db-object conditions)))
([^DB db ^String collection ^Map conditions]
(.remove (.getCollection db (name collection)) (to-db-object conditions))))
"Removes objects from the database."
([^DB db ^String coll]
(.remove (.getCollection db (name coll)) (to-db-object {})))
([^DB db ^String coll ^Map conditions]
(.remove (.getCollection db (name coll)) (to-db-object conditions))))
(defn ^WriteResult remove-by-id
"Removes a single document with given id"
([^String collection id]
(remove-by-id monger.core/*mongodb-database* collection id))
([^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})))))
[^DB db ^String coll id]
(check-not-nil! id "id must not be nil")
(let [coll (.getCollection db (name coll))]
(.remove coll (to-db-object {:_id id}))))
(defn purge-many
"Purges (removes all documents from) multiple collections. Intended
to be used in test environments."
[^DB db xs]
(doseq [coll xs]
(remove db coll)))
;;
;; monger.collection/create-index
;;
(defn create-index
"Forces creation of index on a set of fields, if one does not already exists.
EXAMPLES
;; Will create an index on the \"language\" field
(monger.collection/create-index collection {\"language\" 1})
(monger.collection/create-index collection {\"language\" 1} {:unique true :name \"unique_language\"})
"
([^String collection ^Map keys]
(.createIndex (.getCollection monger.core/*mongodb-database* (name collection)) (as-field-selector keys)))
([^String collection ^Map keys options]
(.createIndex (.getCollection monger.core/*mongodb-database* (name collection))
(as-field-selector keys)
(to-db-object options)))
([^DB db ^String collection ^Map keys ^Map options]
(.createIndex (.getCollection db (name collection))
"Forces creation of index on a set of fields, if one does not already exists."
([^DB db ^String coll ^Map keys]
(.createIndex (.getCollection db (name coll)) (as-field-selector keys)))
([^DB db ^String coll ^Map keys ^Map options]
(.createIndex (.getCollection db (name coll))
(as-field-selector keys)
(to-db-object options))))
@ -531,25 +420,17 @@
Options are:
:unique (boolean) to create a unique index
:name (string) to specify a custom index name and not rely on the generated one
EXAMPLES
;; create a regular index
(monger.collection/ensure-index \"documents\" {\"language\" 1})
;; create a unique index
(monger.collection/ensure-index \"pages\" {:url 1} {:unique true})
"
([^String collection ^Map keys]
(.ensureIndex (.getCollection monger.core/*mongodb-database* (name collection)) (as-field-selector keys)))
([^String collection ^Map keys ^Map options]
(.ensureIndex (.getCollection monger.core/*mongodb-database* (name collection))
:name (string) to specify a custom index name and not rely on the generated one"
([^DB db ^String coll ^Map keys]
(.createIndex (.getCollection db (name coll)) (as-field-selector keys)))
([^DB db ^String coll ^Map keys ^Map options]
(.createIndex (.getCollection db (name coll))
(as-field-selector keys)
(to-db-object options)))
([^String collection ^Map keys ^String name ^Boolean unique?]
(.ensureIndex (.getCollection monger.core/*mongodb-database* (name collection))
([^DB db ^String coll ^Map keys ^String index-name unique?]
(.createIndex (.getCollection db (name coll))
(as-field-selector keys)
name
index-name
unique?)))
@ -558,15 +439,9 @@
;;
(defn indexes-on
"Return a list of the indexes for this collection.
EXAMPLES
(monger.collection/indexes-on collection)
"
[^String collection]
(from-db-object (.getIndexInfo (.getCollection monger.core/*mongodb-database* (name collection))) true))
"Return a list of the indexes for this collection."
[^DB db ^String coll]
(from-db-object (.getIndexInfo (.getCollection db (name coll))) true))
;;
@ -575,17 +450,15 @@
(defn drop-index
"Drops an index from this collection."
([^String collection ^String idx-name]
(.dropIndex (.getCollection monger.core/*mongodb-database* (name collection)) idx-name))
([^DB db ^String collection ^String idx-name]
(.dropIndex (.getCollection db (name collection)) idx-name)))
[^DB db ^String coll idx]
(if (string? idx)
(.dropIndex (.getCollection db (name coll)) ^String idx)
(.dropIndex (.getCollection db (name coll)) (to-db-object idx))))
(defn drop-indexes
"Drops all indixes from this collection."
([^String collection]
(.dropIndexes (.getCollection monger.core/*mongodb-database* (name collection))))
([^DB db ^String collection]
(.dropIndexes (.getCollection db (name collection)))))
[^DB db ^String coll]
(.dropIndexes (.getCollection db (name coll))))
;;
@ -594,49 +467,32 @@
(defn exists?
"Checks weather collection with certain name exists.
EXAMPLE:
(monger.collection/exists? \"coll\")
"
([^String collection]
(.collectionExists monger.core/*mongodb-database* collection))
([^DB db ^String collection]
(.collectionExists db collection)))
"Checks whether collection with certain name exists."
([^DB db ^String coll]
(.collectionExists db coll)))
(defn create
"Creates a collection with a given name and options."
([^String collection ^Map options]
(.createCollection monger.core/*mongodb-database* collection (to-db-object options)))
([^DB db ^String collection ^Map options]
(.createCollection db collection (to-db-object options))))
"Creates a collection with a given name and options.
Options are:
:capped (pass true to create a capped collection)
:max (number of documents)
:size (max allowed size of the collection, in bytes)"
[^DB db ^String coll ^Map options]
(.createCollection db coll (to-db-object options)))
(defn drop
"Deletes collection from database.
EXAMPLE:
(monger.collection/drop \"collection-to-drop\")
"
([^String collection]
(.drop (.getCollection monger.core/*mongodb-database* (name collection))))
([^DB db ^String collection]
(.drop (.getCollection db (name collection)))))
"Deletes collection from database."
[^DB db ^String coll]
(.drop (.getCollection db (name coll))))
(defn rename
"Renames collection.
EXAMPLE:
(monger.collection/rename \"old_name\" \"new_name\")
"
([^String from, ^String to]
(.rename (.getCollection monger.core/*mongodb-database* from) to))
([^String from ^String to ^Boolean drop-target]
(.rename (.getCollection monger.core/*mongodb-database* from) to drop-target))
([^DB db ^String from ^String to ^Boolean drop-target]
(.rename (.getCollection db from) to drop-target)))
"Renames collection."
([^DB db ^String from, ^String to]
(.rename (.getCollection db (name from)) (name to)))
([^DB db ^String from ^String to drop-target?]
(.rename (.getCollection db (name from)) (name to) drop-target?)))
;;
;; Map/Reduce
@ -644,11 +500,11 @@
(defn map-reduce
"Performs a map reduce operation"
([^String collection ^String js-mapper ^String js-reducer ^String output ^Map query]
(let [coll (.getCollection monger.core/*mongodb-database* (name collection))]
([^DB db ^String coll ^String js-mapper ^String js-reducer ^String output ^Map query]
(let [coll (.getCollection db (name coll))]
(.mapReduce coll js-mapper js-reducer output (to-db-object query))))
([^String collection ^String js-mapper ^String js-reducer ^String output ^MapReduceCommand$OutputType output-type ^Map query]
(let [coll (.getCollection monger.core/*mongodb-database* (name collection))]
([^DB db ^String coll ^String js-mapper ^String js-reducer ^String output ^MapReduceCommand$OutputType output-type ^Map query]
(let [coll (.getCollection db (name coll))]
(.mapReduce coll js-mapper js-reducer output output-type (to-db-object query)))))
@ -658,39 +514,55 @@
(defn distinct
"Finds distinct values for a key"
([^String collection ^String key]
(.distinct (.getCollection monger.core/*mongodb-database* (name collection)) ^String (to-db-object key)))
([^String collection ^String key ^Map query]
(.distinct (.getCollection monger.core/*mongodb-database* (name collection)) ^String (to-db-object key) (to-db-object query)))
([^DB db ^String collection ^String key ^Map query]
(.distinct (.getCollection db (name collection)) ^String (to-db-object key) (to-db-object query))))
([^DB db ^String coll ^String key]
(.distinct (.getCollection db (name coll)) ^String (to-db-object key)))
([^DB db ^String coll ^String key ^Map query]
(.distinct (.getCollection db (name coll)) ^String (to-db-object key) (to-db-object query))))
;;
;; create/capped collections
;;
(defn create
"Creates a collection. Options are: :capped (pass true to create a capped collection), :max (number of documents)
and :size (max allowed size of the collection, in bytes)."
[^String collection options]
(.createCollection ^DB monger.core/*mongodb-database* collection (to-db-object options)))
;;
;; Aggregation
;;
(defn- build-aggregation-options
^AggregationOptions
[{:keys [^Boolean allow-disk-use cursor ^Long max-time]}]
(cond-> (AggregationOptions/builder)
allow-disk-use (.allowDiskUse allow-disk-use)
cursor (.outputMode AggregationOptions$OutputMode/CURSOR)
max-time (.maxTime max-time TimeUnit/MILLISECONDS)
(:batch-size cursor) (.batchSize (int (:batch-size cursor)))
true .build))
(defn aggregate
"Performs aggregation query. MongoDB 2.1/2.2+ only.
"Executes an aggregation query. MongoDB 2.2+ only.
Accepts the options :allow-disk-use and :cursor (a map with the :batch-size
key), as described in the MongoDB manual. Additionally, the :max-time option
is supported, for specifying a limit on the execution time of the query in
milliseconds.
:keywordize option that control if resulting map keys will be turned into keywords, default is true.
See http://docs.mongodb.org/manual/applications/aggregation/ to learn more."
[^String collection stages]
(let [res (monger.core/command {:aggregate collection :pipeline stages})]
;; this is what DBCollection#distinct does. Turning a blind eye!
(.throwOnError res)
(map #(from-db-object % true) (.get res "result"))))
[^DB db ^String coll stages & opts]
(let [coll (.getCollection db (name coll))
agg-opts (build-aggregation-options opts)
pipe (into-array-list (to-db-object stages))
res (.aggregate coll pipe agg-opts)
{:keys [^Boolean keywordize]
:or {keywordize true}} opts]
(map #(from-db-object % keywordize) (iterator-seq res))))
(defn explain-aggregate
"Returns the explain plan for an aggregation query. MongoDB 2.2+ only.
See http://docs.mongodb.org/manual/applications/aggregation/ to learn more."
[^DB db ^String coll stages & opts]
(let [coll (.getCollection db (name coll))
agg-opts (build-aggregation-options opts)
pipe (into-array-list (to-db-object stages))
res (.explainAggregate coll pipe agg-opts)]
(from-db-object res true)))
;;
;; Misc
;;
@ -701,5 +573,5 @@
(defn system-collection?
"Evaluates to true if the given collection name refers to a system collection. System collections
are prefixed with system. or fs. (default GridFS collection prefix)"
[^String collection]
(re-find system-collection-pattern collection))
[^String coll]
(re-find system-collection-pattern coll))

View file

@ -1,85 +1,108 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;; Copyright (c) 2012 Toby Hede
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; Copyright (c) 2012 Toby Hede
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Provides convenience functions for performing most commonly used MongoDB commands.
For a lower-level API that gives maximum flexibility, see `monger.core/command`. To use
MongoDB 2.2 Aggregation Framework, see `monger.collection/aggregate`.
(ns monger.command
"Provides convenience functions for performing most commonly used MongoDB commands.
For a lower-level API that gives maximum flexibility, see `monger.core/command`. To use
MongoDB 2.2 Aggregation Framework, see `monger.collection/aggregate`.
Related documentation guides:
Related documentation guides:
* http://clojuremongodb.info/articles/commands.html
* http://clojuremongodb.info/articles/aggregation.html
* http://clojuremongodb.info/articles/mapreduce.html"}
monger.command
(:require monger.core)
(:use monger.conversion)
(:import com.mongodb.DB))
* http://clojuremongodb.info/articles/commands.html
* http://clojuremongodb.info/articles/aggregation.html
* http://clojuremongodb.info/articles/mapreduce.html"
(:require monger.core
[monger.conversion :refer :all])
(:import [com.mongodb MongoClient DB DBObject]))
;;
;; API
;;
(defn admin-command
"Executes a command on the admin database"
[^MongoClient conn m]
(monger.core/command (monger.core/admin-db conn) m))
(defn raw-admin-command
"Executes a command on the admin database"
[^MongoClient conn ^DBObject cmd]
(monger.core/raw-command (monger.core/admin-db conn) cmd))
(defn collection-stats
([collection]
(collection-stats monger.core/*mongodb-database* collection))
([^DB database collection]
(monger.core/command database { :collstats collection })))
[^DB database collection]
(monger.core/command database {:collstats collection}))
(defn db-stats
([]
(db-stats monger.core/*mongodb-database*))
([^DB database]
(monger.core/command database {:dbStats 1 })))
[^DB database]
(monger.core/command database {:dbStats 1}))
(defn reindex-collection
"Forces an existing collection to be reindexed using the reindexCollection command"
([^String collection]
(reindex-collection monger.core/*mongodb-database* collection))
([^DB database ^String collection]
(monger.core/command database { :reIndex collection })))
[^DB database ^String collection]
(monger.core/command database {:reIndex collection}))
(defn rename-collection
"Changes the name of an existing collection using the renameCollection command"
([^String from ^String to]
(reindex-collection monger.core/*mongodb-database* from to))
([^DB database ^String from ^String to]
(monger.core/command database { :renameCollection from :to to })))
[^DB db ^String from ^String to]
(monger.core/command db (sorted-map :renameCollection from :to to)))
(defn convert-to-capped
"Converts an existing, non-capped collection to a capped collection using the convertToCapped command"
([^String collection ^long size]
(convert-to-capped monger.core/*mongodb-database* collection size))
([^DB database ^String collection ^long size]
(monger.core/command database {:convertToCapped collection :size size})))
[^DB db ^String collection ^long size]
(monger.core/command db (sorted-map :convertToCapped collection :size size)))
(defn empty-capped
"Removes all documents from a capped collection using the emptycapped command"
([^String collection]
(empty-capped monger.core/*mongodb-database* collection))
([^DB database ^String collection]
(monger.core/command database {:emptycapped collection})))
[^DB db ^String collection]
(monger.core/command db {:emptycapped collection}))
(defn compact
"Rewrites and defragments a single collection using the compact command. This also forces all indexes on the collection to be rebuilt"
([^String collection]
(compact monger.core/*mongodb-database* collection))
([^DB database ^String collection]
(monger.core/command database {:compact collection})))
[^DB db ^String collection]
(monger.core/command db {:compact collection}))
(defn server-status
([]
(server-status monger.core/*mongodb-database*))
([^DB database]
(monger.core/command database {:serverStatus 1 })))
[^DB db]
(monger.core/command db {:serverStatus 1}))
(defn top
[]
(monger.core/command (monger.core/get-db "admin") {:top 1}))
[^MongoClient conn]
(monger.core/command (monger.core/admin-db conn) {:top 1}))

View file

@ -0,0 +1,44 @@
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.constraints)
;;
;; API
;;
(definline check-not-nil!
[ref ^String message]
`(when (nil? ~ref)
(throw (IllegalArgumentException. ~message))))

View file

@ -1,40 +1,53 @@
;; Original author is Andrew Boekhoff
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Portions of the code are Copyright (c) 2009 Andrew Boekhoff
;; Copyright (c) 2011-2012 Michael S. Klishin
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
;; in the Software without restriction, including without limitation the rights
;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;; copies of the Software, and to permit persons to whom the Software is
;; furnished to do so, subject to the following conditions:
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;; THE SOFTWARE.
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Portions of the code are Copyright (c) 2009 Andrew Boekhoff
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Provides functions that convert between MongoDB Java driver classes (DBObject, DBList) and Clojure
data structures (maps, collections). Most of the time, application developers won't need to use these
functions directly because Monger Query DSL and many other functions convert documents to Clojure sequences and
maps automatically. However, this namespace is part of the public API and guaranteed to be stable between minor releases.
(ns monger.conversion
"Provides functions that convert between MongoDB Java driver classes (DBObject, DBList) and Clojure
data structures (maps, collections). Most of the time, application developers won't need to use these
functions directly because Monger Query DSL and many other functions convert documents to Clojure sequences and
maps automatically. However, this namespace is part of the public API and guaranteed to be stable between minor releases.
Related documentation guides:
Related documentation guides:
* http://clojuremongodb.info/articles/inserting.html
* http://clojuremongodb.info/articles/querying.html"}
monger.conversion
* http://clojuremongodb.info/articles/inserting.html
* http://clojuremongodb.info/articles/querying.html"
(:import [com.mongodb DBObject BasicDBObject BasicDBList DBCursor]
[clojure.lang IPersistentMap Named Keyword Ratio]
[java.util List Map Date Set]
org.bson.types.ObjectId))
org.bson.types.ObjectId
(org.bson.types Decimal128)))
(defprotocol ConvertToDBObject
(^com.mongodb.DBObject to-db-object [input] "Converts given piece of Clojure data to BasicDBObject MongoDB Java driver uses"))
@ -42,7 +55,7 @@
(extend-protocol ConvertToDBObject
nil
(to-db-object [input]
input)
nil)
String
(to-db-object [^String input]
@ -82,8 +95,8 @@
DBObject
(to-db-object [^DBObject input] input)
com.novemberain.monger.DBRef
(to-db-object [^com.novemberain.monger.DBRef dbref]
com.mongodb.DBRef
(to-db-object [^com.mongodb.DBRef dbref]
dbref)
Object
@ -92,55 +105,44 @@
(declare associate-pairs)
(defprotocol ConvertFromDBObject
(from-db-object [input keywordize] "Converts given DBObject instance to a piece of Clojure data"))
(extend-protocol ConvertFromDBObject
nil
(from-db-object [input keywordize] input)
(from-db-object [_ _] nil)
Object
(from-db-object [input keywordize] input)
(from-db-object [input _] input)
Map
(from-db-object [^Map input keywordize]
(associate-pairs (.entrySet input) keywordize))
Decimal128
(from-db-object [^Decimal128 input _]
(.bigDecimalValue input))
List
(from-db-object [^List input keywordize]
(vec (map #(from-db-object % keywordize) input)))
(mapv #(from-db-object % keywordize) input))
BasicDBList
(from-db-object [^BasicDBList input keywordize]
(vec (map #(from-db-object % keywordize) input)))
(mapv #(from-db-object % keywordize) input))
com.mongodb.DBRef
(from-db-object [^com.mongodb.DBRef input keywordize]
(com.novemberain.monger.DBRef. input))
(from-db-object [^com.mongodb.DBRef input _]
input)
DBObject
(from-db-object [^DBObject input keywordize]
;; DBObject provides .toMap, but the implementation in
;; subclass GridFSFile unhelpfully throws
;; UnsupportedOperationException. This part is taken from congomongo and
;; may need revisiting at a later point. MK.
(associate-pairs (for [key-set (.keySet input)] [key-set (.get input key-set)])
keywordize)))
(defn- associate-pairs [pairs keywordize]
;; Taking the keywordize test out of the fn reduces derefs
;; dramatically, which was the main barrier to matching pure-Java
;; performance for this marshalling. Taken from congomongo. MK.
(reduce (if keywordize
(fn [m [^String k v]]
(assoc m (keyword k) (from-db-object v true)))
(fn [m [^String k v]]
(assoc m k (from-db-object v false))))
{} (reverse pairs)))
;; UnsupportedOperationException.
(persistent!
(reduce (if keywordize
(fn [m ^String k]
(assoc! m (keyword k) (from-db-object (.get input k) true)))
(fn [m ^String k]
(assoc! m k (from-db-object (.get input k) false))))
(transient {}) (.keySet input)))))
(defprotocol ConvertToObjectId

View file

@ -1,28 +1,53 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:author "Michael S. Klishin"
:doc "Thin idiomatic wrapper around MongoDB Java client. monger.core includes
fundamental functions that perform database/replica set connection, set default write concern, default database, performing commands
and so on. Most of the functionality is in other monger.* namespaces, in particular monger.collection, monger.query and monger.gridfs
(ns monger.core
"Thin idiomatic wrapper around MongoDB Java client. monger.core includes
fundamental functions that perform database/replica set connection, set default write concern, default database, performing commands
and so on. Most of the functionality is in other monger.* namespaces, in particular monger.collection, monger.query and monger.gridfs
Related documentation guides:
Related documentation guides:
* http://clojuremongodb.info/articles/connecting.html
* http://clojuremongodb.info/articles/commands.html
* http://clojuremongodb.info/articles/gridfs.html"}
monger.core
* http://clojuremongodb.info/articles/connecting.html
* http://clojuremongodb.info/articles/commands.html
* http://clojuremongodb.info/articles/gridfs.html"
(:refer-clojure :exclude [count])
(:use [monger.conversion])
(:import [com.mongodb Mongo MongoURI DB WriteConcern DBObject DBCursor Bytes MongoOptions ServerAddress MapReduceOutput]
(:require [monger.conversion :refer :all]
[monger.util :refer [into-array-list]])
(:import [com.mongodb MongoClient MongoClientURI MongoCredential DB WriteConcern DBObject DBCursor Bytes
MongoClientOptions MongoClientOptions$Builder ServerAddress MapReduceOutput MongoException]
[com.mongodb.gridfs GridFS]
[java.util Map ArrayList]))
[java.util Map]))
;;
;; Defaults
@ -31,103 +56,78 @@
(def ^:dynamic ^String *mongodb-host* "127.0.0.1")
(def ^:dynamic ^long *mongodb-port* 27017)
(declare ^:dynamic ^Mongo *mongodb-connection*)
(declare ^:dynamic ^DB *mongodb-database*)
(def ^:dynamic ^WriteConcern *mongodb-write-concern* WriteConcern/SAFE)
(declare ^:dynamic ^GridFS *mongodb-gridfs*)
(def ^:dynamic ^WriteConcern *mongodb-write-concern* WriteConcern/ACKNOWLEDGED)
;;
;; API
;;
(defn ^com.mongodb.Mongo connect
(defn ^MongoClient connect
"Connects to MongoDB. When used without arguments, connects to
Arguments:
:host (*mongodb-host* by default)
:port (*mongodb-port* by default)
EXAMPLES
(monger.core/connect)
(monger.core/connect { :host \"db3.intranet.local\", :port 27787 })
;; Connecting to a replica set with a couple of seeds
(let [^MongoOptions opts (mg/mongo-options :threads-allowed-to-block-for-connection-multiplier 300)
seeds [[\"192.168.1.1\" 27017] [\"192.168.1.2\" 27017] [\"192.168.1.1\" 27018]]
sas (map #(apply mg/server-address %) seeds)]
(mg/connect! sas opts))
"
:host (\"127.0.0.1\" by default)
:port (27017 by default)"
{:arglists '([]
[server-address options]
[server-address options credentials]
[[server-address & more] options]
[{ :keys [host port uri] :or { host *mongodb-host* port *mongodb-port* }}])}
[{:keys [host port uri] :or { host *mongodb-host* port *mongodb-port*}}])}
([]
(Mongo.))
([server-address ^MongoOptions options]
(MongoClient.))
([server-address ^MongoClientOptions options]
(if (coll? server-address)
;; connect to a replica set
(let [server-list ^ArrayList (ArrayList. ^java.util.Collection server-address)]
(Mongo. server-list options))
(let [server-list (into-array-list server-address)]
(MongoClient. server-list options))
;; connect to a single instance
(Mongo. ^ServerAddress server-address options)))
(MongoClient. ^ServerAddress server-address options)))
([server-address ^MongoClientOptions options credentials]
(let [creds (into-array-list (if (coll? credentials)
credentials
[credentials]))]
(if (coll? server-address)
(let [server-list (into-array-list server-address)]
(MongoClient. server-list ^java.util.List creds options))
(MongoClient. ^ServerAddress server-address ^java.util.List creds options))))
([{ :keys [host port uri] :or { host *mongodb-host* port *mongodb-port* }}]
(Mongo. ^String host ^Long port)))
(if uri
(MongoClient. (MongoClientURI. uri))
(MongoClient. ^String host ^Long port))))
(defn ^MongoClient connect-with-credentials
"Connect with provided credentials and default options"
([credentials]
(connect-with-credentials *mongodb-host* *mongodb-port* credentials))
([^String hostname credentials]
(connect-with-credentials hostname *mongodb-port* credentials))
([^String hostname ^long port credentials]
(MongoClient. (into-array-list [(ServerAddress. hostname port)])
(into-array-list (if (coll? credentials)
credentials
[credentials])))))
(defn get-db-names
"Gets a list of all database names present on the server"
([]
(get-db-names *mongodb-connection*))
([^Mongo connection]
(set (.getDatabaseNames connection))))
[^MongoClient conn]
(set (.getDatabaseNames conn)))
(defn ^com.mongodb.DB get-db
"Get database reference by name.
(defn ^DB get-db
"Get database reference by name."
[^MongoClient conn ^String name]
(.getDB conn name))
EXAMPLES
(monger.core/get-db \"myapp_production\")
(monger.core/get-db connection \"myapp_production\")"
([]
*mongodb-database*)
([^String name]
(.getDB *mongodb-connection* name))
([^Mongo connection ^String name]
(.getDB connection name)))
(defn ^com.mongodb.DB current-db
"Returns currently used database"
[]
*mongodb-database*)
(defn authenticate
([^String db ^String username ^chars password]
(authenticate *mongodb-connection* db username password))
([^Mongo connection ^String db ^String username ^chars password]
(.authenticate (.getDB connection db) username password)))
(defmacro with-connection
[conn & body]
`(binding [*mongodb-connection* ~conn]
(do ~@body)))
(defmacro with-db
[db & body]
`(binding [*mongodb-database* ~db]
(do ~@body)))
(defmacro with-gridfs
[fs & body]
`(binding [*mongodb-gridfs* ~fs]
(do ~@body)))
(defn drop-db
"Drops a database"
[^MongoClient conn ^String db]
(.dropDatabase conn db))
(defn ^GridFS get-gridfs
"Get GridFS for the given database."
[^MongoClient conn ^String name]
(GridFS. (.getDB conn name)))
(defn server-address
([^String hostname]
@ -135,158 +135,165 @@
([^String hostname ^Long port]
(ServerAddress. hostname port)))
(defn mongo-options
[& { :keys [connections-per-host threads-allowed-to-block-for-connection-multiplier
max-wait-time connect-timeout socket-timeout socket-keep-alive auto-connect-retry max-auto-connect-retry-time
safe w w-timeout fsync j] :or [auto-connect-retry true] }]
(let [mo (MongoOptions.)]
(defn ^MongoClientOptions$Builder mongo-options-builder
[{:keys [add-cluster-listener add-cluster-listeners add-command-listener add-command-listeners
add-connection-pool-listener add-connection-pool-listeners add-server-listener add-server-listeners
add-server-monitor-listener add-server-monitor-listeners always-use-mbeans application-name
codec-registry compressor-list connect-timeout connections-per-host cursor-finalizer-enabled
db-decoder-factory db-encoder-factory description heartbeat-connect-timeout heartbeat-frequency
heartbeat-socket-timeout local-threshold max-connection-idle-time max-connection-life-time
max-wait-time min-connections-per-host min-heartbeat-frequency read-concern read-preference
required-replica-set-name retry-writes server-selection-timeout server-selector socket-keep-alive
socket-factory socket-timeout ssl-context ssl-enabled ssl-invalid-host-name-allowed
threads-allowed-to-block-for-connection-multiplier uuid-representation write-concern]}]
(let [mob (MongoClientOptions$Builder.)]
(when add-cluster-listener
(.addClusterListener mob add-cluster-listener))
(when add-cluster-listeners
(doseq [cluster-listener add-cluster-listeners]
(.addClusterListener mob cluster-listener)))
(when add-command-listener
(.addCommandListener mob add-command-listener))
(when add-command-listeners
(doseq [command-listener add-command-listeners]
(.addCommandListener mob command-listener)))
(when add-connection-pool-listener
(.addConnectionPoolListener mob add-connection-pool-listener))
(when add-connection-pool-listeners
(doseq [connection-pool-listener add-connection-pool-listeners]
(.addConnectionPoolListener mob connection-pool-listener)))
(when add-server-listener
(.addServerListener mob add-server-listener))
(when add-server-listeners
(doseq [server-listener add-server-listeners]
(.addServerListener mob server-listener)))
(when add-server-monitor-listener
(.addServerMonitorListener mob add-server-monitor-listener))
(when add-server-monitor-listeners
(doseq [server-monitor-listener add-server-monitor-listeners]
(.addServerMonitorListener mob server-monitor-listener)))
(when always-use-mbeans
(.alwaysUseMBeans mob always-use-mbeans))
(when application-name
(.applicationName mob application-name))
(when always-use-mbeans
(.alwaysUseMBeans mob always-use-mbeans))
(when codec-registry
(.codecRegistry mob codec-registry))
(when compressor-list
(.compressorList mob compressor-list))
(when connections-per-host
(set! (. mo connectionsPerHost) connections-per-host))
(when threads-allowed-to-block-for-connection-multiplier
(set! (. mo threadsAllowedToBlockForConnectionMultiplier) threads-allowed-to-block-for-connection-multiplier))
(when max-wait-time
(set! (. mo maxWaitTime) max-wait-time))
(.connectionsPerHost mob connections-per-host))
(when connect-timeout
(set! (. mo connectTimeout) connect-timeout))
(when socket-timeout
(set! (. mo socketTimeout) socket-timeout))
(.connectTimeout mob connect-timeout))
(when cursor-finalizer-enabled
(.cursorFinalizerEnabled mob cursor-finalizer-enabled))
(when db-decoder-factory
(.dbDecoderFactory mob db-decoder-factory))
(when db-encoder-factory
(.dbEncoderFactory mob db-encoder-factory))
(when description
(.description mob description))
(when heartbeat-connect-timeout
(.heartbeatConnectTimeout mob heartbeat-connect-timeout))
(when heartbeat-frequency
(.heartbeatFrequency mob heartbeat-frequency))
(when heartbeat-socket-timeout
(.heartbeatSocketTimeout mob heartbeat-socket-timeout))
(when ssl-context
(.sslContext mob ssl-context))
(when local-threshold
(.localThreshold mob local-threshold))
(when max-connection-idle-time
(.maxConnectionIdleTime mob max-connection-idle-time))
(when max-wait-time
(.maxWaitTime mob max-wait-time))
(when max-connection-life-time
(.maxConnectionLifeTime mob max-connection-life-time))
(when min-connections-per-host
(.minConnectionsPerHost mob min-connections-per-host))
(when min-heartbeat-frequency
(.minHeartbeatFrequency mob min-heartbeat-frequency))
(when read-concern
(.readConcern mob read-concern))
(when read-preference
(.readPreference mob read-preference))
(when required-replica-set-name
(.requiredReplicaSetName mob required-replica-set-name))
(when retry-writes
(.retryWrites mob retry-writes))
(when server-selection-timeout
(.serverSelectionTimeout mob server-selection-timeout))
(when server-selector
(.serverSelector mob server-selector))
(when socket-keep-alive
(set! (. mo socketKeepAlive) socket-keep-alive))
(when auto-connect-retry
(set! (. mo autoConnectRetry) auto-connect-retry))
(when max-auto-connect-retry-time
(set! (. mo maxAutoConnectRetryTime) max-auto-connect-retry-time))
(when safe
(set! (. mo safe) safe))
(when w
(set! (. mo w) w))
(when w-timeout
(set! (. mo wtimeout) w-timeout))
(when j
(set! (. mo j) j))
(when fsync
(set! (. mo fsync) fsync))
mo))
(.socketKeepAlive mob socket-keep-alive))
(when socket-factory
(.socketFactory mob socket-factory))
(when socket-timeout
(.socketTimeout mob socket-timeout))
(when ssl-enabled
(.sslEnabled mob ssl-enabled))
(when ssl-invalid-host-name-allowed
(.sslInvalidHostNameAllowed mob ssl-invalid-host-name-allowed))
(when threads-allowed-to-block-for-connection-multiplier
(.threadsAllowedToBlockForConnectionMultiplier mob threads-allowed-to-block-for-connection-multiplier))
(when uuid-representation
(.uuidRepresentation mob uuid-representation))
(when write-concern
(.writeConcern mob write-concern))
mob))
(defn ^MongoClientOptions mongo-options
[opts]
(let [mob (mongo-options-builder opts)]
(.build mob)))
(defn set-connection!
"Sets given MongoDB connection as default by altering *mongodb-connection* var"
^Mongo [^Mongo conn]
(alter-var-root (var *mongodb-connection*) (constantly conn)))
(defn disconnect
"Closes default connection to MongoDB"
[^MongoClient conn]
(.close conn))
(defn connect!
"Connect to MongoDB, store connection in the *mongodb-connection* var"
^Mongo [& args]
(let [c (apply connect args)]
(set-connection! c)))
(def ^:const admin-db-name "admin")
(defn set-db!
"Sets *mongodb-database* var to given db, updates *mongodb-gridfs* var state. Recommended to be used for
applications that only use one database."
[db]
(alter-var-root (var *mongodb-database*) (constantly db))
(alter-var-root (var *mongodb-gridfs*) (constantly (GridFS. db))))
(def ^{:doc "Combines set-db! and get-db, so (use-db \"mydb\") is the same as (set-db! (get-db \"mydb\"))"}
use-db! (comp set-db! get-db))
(defn ^DB admin-db
"Returns admin database"
[^MongoClient conn]
(get-db conn admin-db-name))
(defn set-default-write-concern!
[wc]
"Set *mongodb-write-concert* var to :wc
Unlike the official Java driver, Monger uses WriteConcern/SAFE by default. We think defaults should be safe first
and WebScale fast second."
"Sets *mongodb-write-concert*"
(alter-var-root #'*mongodb-write-concern* (constantly wc)))
(defn connect-via-uri!
"Connects to MongoDB using a URI, sets up default connection and database. Commonly used for PaaS-based applications,
for example, running on Heroku. If username and password are provided, performs authentication."
[uri]
(let [uri (MongoURI. uri)
;; yes, you are not hallucinating. A class named MongoURI has a method called connectDB.
;; I call it "college OOP". Or maybe "don't give a shit" OOP.
db (.connectDB uri)
conn (.getMongo db)
user (.getUsername uri)
pwd (.getPassword uri)]
;; I hope that whoever wrote the MongoDB Java driver connection/authentication parts
;; wasn't sober while at it. MK.
;;
;; First we set connection, then DB, then authentcate
(set-connection! conn)
(when (and user pwd)
(when-not (authenticate (.getName db) user pwd)
(throw (IllegalArgumentException. (format "Could not authenticate with MongoDB. Either database name or credentials are invalid. Database name: %s, username: %s" (.getName db) user)))))
;; only do this *after* we authenticated because set-db! will try to set up a default GridFS instance. MK.
(when db
(set-db! db))
conn))
(defn connect-via-uri
"Connects to MongoDB using a URI, returns the connection and database as a map with :conn and :db.
Commonly used for PaaS-based applications, for example, running on Heroku.
If username and password are provided, performs authentication."
[^String uri-string]
(let [uri (MongoClientURI. uri-string)
conn (MongoClient. uri)]
(if-let [dbName (.getDatabase uri)]
{:conn conn :db (.getDB conn dbName)}
(throw (IllegalArgumentException. "No database name specified in URI. Monger requires a database to be explicitly configured.")))))
(defn ^com.mongodb.CommandResult command
"Runs a database command (please check MongoDB documentation for the complete list of commands). Some common commands
are:
"Runs a database command (please check MongoDB documentation for the complete list of commands).
{ :buildinfo 1 } returns version number and build information about the current MongoDB server, should be executed via admin DB.
Ordering of keys in the command document may matter. Please use sorted maps instead of map literals, for example:
(array-map :near 50 :test 430 :num 10)
{ :collstats collection-name [ :scale scale ] } returns stats about given collection.
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."
[^DB database ^Map cmd]
(.command ^DB database ^DBObject (to-db-object cmd)))
{ :dbStats 1 } returns the stats of current database
{ :dropDatabase 1 } deletes the current database
{ :findAndModify find-and-modify-config } runs find, modify and return for the given query.
Takes :query, :sory, :remove, :update, :new, :fields and :upsert arguments.
Please refer MongoDB documentation for details. http://www.mongodb.org/display/DOCS/findAndModify+Command
{ :fsync config } performs a full fsync, that flushes all pending writes to database, provides an optional write lock that will make
backups easier.
Please refer MongoDB documentation for details :http://www.mongodb.org/display/DOCS/fsync+Command
{ :getLastError 1 } returns the status of the last operation on current connection.
{ :group group-config } performs grouping aggregation, docs and support for grouping are TBD in Monger.
{ :listCommands 1 } displays the list of available commands.
{ :profile new-profile-level } sets the database profiler to profile level N.
{ :reIndex coll } performs re-index on a given collection.
{ :renameCollection old-name :to new-name } renames collection from old-name to new-name
{ :repairDatabase 1 } repair and compact the current database (may be very time-consuming, depending on DB size)
Replica set commands
{ :isMaster 1 } checks if this server is a master server.
{ :replSetGetStatus 1 } get the status of a replica set.
{ :replSetInitiate replica-config } initiate a replica set with given config.
{ :replSetReconfig replica-config } set a given config for replica set.
{ :replSetStepDown seconds } manually tell a member to step down as primary. It will become primary again after specified amount of seconds.
{ :replSetFreeze seconds } freeze state of member, call with 0 to unfreeze.
{ :resync 1 } start a full resync of a replica slave
For more information, please refer Mongodb Replica Set Command guide: http://www.mongodb.org/display/DOCS/Replica+Set+Commands
{ :serverStatus 1 } gets administrative statistics about the server.
{ :shutdown 1 } shuts the MongoDB server down.
{ :top 1 } get a breakdown of usage by collection.
{ :validate namespace-name } validate the namespace (collection or index). May be very time-consuming, depending on DB size.
For :distinct, :count, :drop, :dropIndexes, :mapReduce we suggest to use monger/collection #distinct, #count, #drop, #dropIndexes, :mapReduce respectively.
"
([^Map cmd]
(.command ^DB *mongodb-database* ^DBObject (to-db-object cmd)))
([^DB database ^Map cmd]
(.command ^DB database ^DBObject (to-db-object cmd))))
(defn ^com.mongodb.CommandResult raw-command
"Like monger.core/command but accepts DBObjects"
[^DB database ^DBObject cmd]
(.command database cmd))
(defprotocol Countable
(count [this] "Returns size of the object"))
@ -301,23 +308,3 @@
;; MongoDB Java driver could use a lot more specific type than Iterable but
;; it always uses DBCollection#find to popular result set. MK.
(.count ^DBCursor (.results this))))
(defn ^DBObject get-last-error
"Returns the the error (if there is one) from the previous operation on this connection.
The result of this command looks like:
#<CommandResult { \"serverUsed\" : \"127.0.0.1:27017\" , \"n\" : 0 , \"connectionId\" : 66 , \"err\" : null , \"ok\" : 1.0}>\"
The value for err will be null if no error occurred, or a description otherwise.
Important note: when calling this method directly, it is undefined which connection \"getLastError\" is called on.
You may need to explicitly use a \"consistent Request\", see requestStart() For most purposes it is better not to call this method directly but instead use WriteConcern."
([]
(get-last-error *mongodb-database*))
([^DB database]
(.getLastError ^DB database))
([^DB database ^Integer w ^Integer wtimeout ^Boolean fsync]
(.getLastError ^DB database w wtimeout fsync))
([^DB database ^WriteConcern write-concern]
(.getLastError ^DB database write-concern)))

View file

@ -0,0 +1,56 @@
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.credentials
"Helper functions for instantiating various types
of credentials."
(:require [clojurewerkz.support.chars :refer :all])
(:import [com.mongodb MongoCredential]))
;;
;; API
;;
(defn ^MongoCredential create
"Creates a MongoCredential instance with an unspecified mechanism.
The client will negotiate the best mechanism based on the
version of the server that the client is authenticating to."
[^String username ^String database pwd]
(MongoCredential/createCredential username database (to-char-array pwd)))
(defn ^MongoCredential x509
"Creates a MongoCredential instance for the X509-based authentication
protocol."
[^String username]
(MongoCredential/createMongoX509Credential username))

View file

@ -0,0 +1,143 @@
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.cursor
"Helper-functions for dbCursor object:
* to initialize new cursor,
* for CRUD functionality of options of dbCursor"
(:import [com.mongodb DB DBCursor Bytes]
[java.util List Map]
[java.lang Integer]
[clojure.lang Keyword])
(:require [monger.core]
[monger.conversion :refer [to-db-object from-db-object as-field-selector]]))
(defn ^DBCursor make-db-cursor
"initializes new db-cursor."
([^DB db ^String coll]
(make-db-cursor db coll {} {}))
([^DB db ^String coll ^Map ref]
(make-db-cursor db coll ref {}))
([^DB db ^String coll ^Map ref fields]
(.find
(.getCollection db (name coll))
(to-db-object ref)
(as-field-selector fields))))
(def cursor-options {:awaitdata Bytes/QUERYOPTION_AWAITDATA
;;:exhaust Bytes/QUERYOPTION_EXHAUST - not human settable
:notimeout Bytes/QUERYOPTION_NOTIMEOUT
:oplogreplay Bytes/QUERYOPTION_OPLOGREPLAY
:partial Bytes/QUERYOPTION_PARTIAL
:slaveok Bytes/QUERYOPTION_SLAVEOK
:tailable Bytes/QUERYOPTION_TAILABLE})
(defn get-options
"Returns map of cursor's options with current state."
[^DBCursor db-cur]
(into {}
(for [[opt option-mask] cursor-options]
[opt (< 0 (bit-and (.getOptions db-cur) option-mask))])))
(defn add-option!
[^DBCursor db-cur ^String opt]
(.addOption db-cur (get cursor-options (keyword opt) 0)))
(defn remove-option!
[^DBCursor db-cur ^String opt]
(.setOptions db-cur (bit-and-not (.getOptions db-cur)
(get cursor-options (keyword opt) 0))))
(defmulti add-options (fn [db-cur opts] (class opts)))
(defmethod add-options Map [^DBCursor db-cur options]
"Changes options by using map of settings, which key specifies name of settings
and boolean value specifies new state of the setting.
usage:
(add-options db-cur {:notimeout true, :tailable false})
returns:
^DBCursor object."
(doseq [[opt value] (seq options)]
(if (= true value)
(add-option! db-cur opt)
(remove-option! db-cur opt)))
db-cur)
(defmethod add-options List [^DBCursor db-cur options]
"Takes list of options and activates these options
usage:
(add-options db-cur [:notimeout :tailable])
returns:
^DBCursor object"
(doseq [opt (seq options)]
(add-option! db-cur opt))
db-cur)
(defmethod add-options Integer [^DBCursor db-cur, option]
"Takes com.mongodb.Byte value and adds it to current settings.
usage:
(add-options db-cur com.mongodb.Bytes/QUERYOPTION_NOTIMEOUT)
returns:
^DBCursor object"
(.addOption db-cur option)
db-cur)
(defmethod add-options Keyword [^DBCursor db-cur, option]
"Takes just one keyword as name of settings and applies it to the db-cursor.
usage:
(add-options db-cur :notimeout)
returns:
^DBCursor object"
(add-option! db-cur option)
db-cur)
(defmethod add-options :default [^DBCursor db-cur, options]
"Using add-options with not supported type of options just passes unchanged cursor"
db-cur)
(defn ^DBCursor reset-options
"Resets cursor options to default value and returns cursor"
[^DBCursor db-cur]
(.resetOptions db-cur)
db-cur)
(defmulti format-as (fn [db-cur as] as))
(defmethod format-as :map [db-cur as]
(map #(from-db-object %1 true) db-cur))
(defmethod format-as :seq [db-cur as]
(seq db-cur))
(defmethod format-as :default [db-cur as]
db-cur)

View file

@ -1,39 +1,62 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;; Copyright (c) 2012 Toby Hede
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; Copyright (c) 2012 Toby Hede
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.db
"Functions that provide operations on databases"
(:refer-clojure :exclude [find remove count drop distinct empty?])
(:import [com.mongodb Mongo DB DBCollection])
(:require monger.core)
(:use monger.conversion))
(:require monger.core
[monger.conversion :refer :all]))
;;
;; API
;;
(defn add-user
"Adds a new user for this db"
([^String username, ^chars password]
(.addUser ^DB monger.core/*mongodb-database* username password))
([^DB database ^String username ^chars password]
(.addUser ^DB database username password)))
[^DB db ^String username ^chars password]
(.addUser db username password))
(defn drop-db
"Drops the currently set database (via core/set-db) or the specified database."
([]
(.dropDatabase ^DB monger.core/*mongodb-database*))
([^DB database]
(.dropDatabase ^DB database)))
[^DB db]
(.dropDatabase db))
(defn get-collection-names
"Returns a set containing the names of all collections in this database."
([]
(set (.getCollectionNames ^DB monger.core/*mongodb-database*)))
([^DB database]
(set (.getCollectionNames ^DB database))))
([^DB db]
(set (.getCollectionNames db))))

View file

@ -1,26 +1,50 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns
^{:doc "Provides functions and macros for working with GridFS: storing files in GridFS, streaming files from GridFS,
finding stored files.
(ns monger.gridfs
"Provides functions and macros for working with GridFS: storing files in GridFS, streaming files from GridFS,
finding stored files.
Related documentation guide: http://clojuremongodb.info/articles/gridfs.html"}
monger.gridfs
Related documentation guide: http://clojuremongodb.info/articles/gridfs.html"
(:refer-clojure :exclude [remove find])
(:require monger.core
[clojure.java.io :as io])
(:use monger.conversion
[clojurewerkz.support.fn :only [fpartial]])
[clojure.java.io :as io]
[monger.conversion :refer :all]
[clojurewerkz.support.fn :refer [fpartial]])
(:import [com.mongodb DB DBObject]
org.bson.types.ObjectId
[com.mongodb.gridfs GridFS GridFSInputFile]
[java.io InputStream File]))
[java.io InputStream ByteArrayInputStream File]))
;;
;; Implementation
@ -42,24 +66,16 @@
(defn remove
([]
(remove {}))
([query]
(.remove ^GridFS monger.core/*mongodb-gridfs* ^DBObject (to-db-object query)))
([^GridFS fs query]
(.remove fs ^DBObject (to-db-object query))))
[^GridFS fs query]
(.remove fs ^DBObject (to-db-object query)))
(defn remove-all
([]
(remove {}))
([^GridFS fs]
(remove fs {})))
[^GridFS fs]
(remove fs {}))
(defn all-files
([]
(.getFileList ^GridFS monger.core/*mongodb-gridfs*))
([query]
(.getFileList ^GridFS monger.core/*mongodb-gridfs* query))
([^GridFS fs]
(.getFileList fs (to-db-object {})))
([^GridFS fs query]
(.getFileList fs query)))
@ -67,10 +83,8 @@
(fpartial from-db-object true))
(defn files-as-maps
([]
(map converter (all-files)))
([query]
(map converter (all-files (to-db-object query))))
([^GridFS fs]
(files-as-maps fs {}))
([^GridFS fs query]
(map converter (all-files fs (to-db-object query)))))
@ -79,27 +93,51 @@
;; Plumbing (low-level API)
;;
(defprotocol InputStreamFactory
(^InputStream to-input-stream [input] "Makes InputStream out of the given input"))
(extend byte-array-type
InputStreamFactory
{:to-input-stream (fn [^bytes input]
(ByteArrayInputStream. input))})
(extend-protocol InputStreamFactory
String
(to-input-stream [^String input]
(io/make-input-stream input {:encoding "UTF-8"}))
File
(to-input-stream [^File input]
(io/make-input-stream input {:encoding "UTF-8"}))
InputStream
(to-input-stream [^InputStream input]
input))
(defprotocol GridFSInputFileFactory
(^com.mongodb.gridfs.GridFSInputFile make-input-file [input] "Makes GridFSInputFile out of the given input"))
(^GridFSInputFile create-gridfs-file [input ^GridFS fs] "Creates a file entry"))
(extend byte-array-type
GridFSInputFileFactory
{:make-input-file (fn [^bytes input]
(.createFile ^GridFS monger.core/*mongodb-gridfs* input))})
{:create-gridfs-file (fn [^bytes input ^GridFS fs]
(.createFile fs input))})
(extend-protocol GridFSInputFileFactory
String
(make-input-file [^String input]
(.createFile ^GridFS monger.core/*mongodb-gridfs* ^InputStream (io/make-input-stream input {:encoding "UTF-8"})))
(create-gridfs-file [^String input ^GridFS fs]
(.createFile fs (io/file input)))
File
(make-input-file [^File input]
(.createFile ^GridFS monger.core/*mongodb-gridfs* ^InputStream (io/make-input-stream input {:encoding "UTF-8"})))
(create-gridfs-file [^File input ^GridFS fs]
(.createFile fs input))
InputStream
(make-input-file [^InputStream input]
(.createFile ^GridFS monger.core/*mongodb-gridfs* ^InputStream input)))
(create-gridfs-file [^InputStream input ^GridFS fs]
(.createFile fs input)))
(defn ^GridFSInputFile make-input-file
[^GridFS fs input]
(create-gridfs-file input fs))
(defmacro store
[^GridFSInputFile input & body]
@ -107,9 +145,8 @@
(.save f# GridFS/DEFAULT_CHUNKSIZE)
(from-db-object f# true)))
;;
;; "New" DSL, a higher-level API
;; Higher-level API
;;
(defn save
@ -142,48 +179,34 @@
;; Finders
;;
(defprotocol Finders
(find [input] "Finds multiple files using given input (an ObjectId, filename or query)")
(find-one [input] "Finds one file using given input (an ObjectId, filename or query)")
(find-maps [input] "Finds multiple files using given input (an ObjectId, filename or query), returning a Clojure map")
(find-one-as-map [input] "Finds one file using given input (an ObjectId, filename or query), returning a Clojure map"))
(defn find
[^GridFS fs query]
(.find fs (to-db-object query)))
(extend-protocol Finders
String
(find [^String input]
(.find ^GridFS monger.core/*mongodb-gridfs* input))
(find-one [^String input]
(.findOne ^GridFS monger.core/*mongodb-gridfs* input))
(find-maps [^String input]
(map converter (find input)))
(find-one-as-map [^String input]
(converter (find-one input)))
(defn find-by-filename
[^GridFS fs ^String filename]
(.find fs (to-db-object {"filename" filename})))
org.bson.types.ObjectId
(find-one [^org.bson.types.ObjectId input]
(.findOne ^GridFS monger.core/*mongodb-gridfs* input))
(find-one-as-map [^org.bson.types.ObjectId input]
(converter (find-one input)))
(defn find-by-md5
[^GridFS fs ^String md5]
(.find fs (to-db-object {"md5" md5})))
(defn find-one
[^GridFS fs query]
(.findOne fs (to-db-object query)))
DBObject
(find [^DBObject input]
(.find ^GridFS monger.core/*mongodb-gridfs* input))
(find-one [^DBObject input]
(.findOne ^GridFS monger.core/*mongodb-gridfs* input))
(find-maps [^DBObject input]
(map converter (find input)))
(find-one-as-map [^DBObject input]
(converter (find-one input)))
(defn find-maps
[^GridFS fs query]
(map converter (find fs query)))
;; using java.util.Map here results in (occasional) recursion
clojure.lang.IPersistentMap
(find [^java.util.Map input]
(find (to-db-object input)))
(find-one [^java.util.Map input]
(find-one (to-db-object input)))
(find-maps [^java.util.Map input]
(find-maps (to-db-object input)))
(find-one-as-map [^java.util.Map input]
(find-one-as-map (to-db-object input))))
(defn find-one-as-map
[^GridFS fs query]
(converter (find-one fs query)))
(defn find-by-id
[^GridFS fs ^ObjectId id]
(.findOne fs id))
(defn find-map-by-id
[^GridFS fs ^ObjectId id]
(converter (find-by-id fs id)))

View file

@ -1,73 +0,0 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns monger.internal.fn)
;;
;; Implementation
;;
(defn- apply-to-values [m f]
"Applies function f to all values in map m"
(into {} (for [[k v] m]
[k (f v)])))
;;
;; API
;;
(defn fpartial
"Like clojure.core/partial but prepopulates last N arguments (first is passed in later)"
[f & args]
(fn [arg & more] (apply f arg (concat args more))))
(defprotocol IFNExpansion
(expand-all [x] "Replaces functions with their invocation results, recursively expands maps, evaluates all other values to themselves")
(expand-all-with [x f] "Replaces functions with their invocation results that function f is applied to, recursively expands maps, evaluates all other values to themselves"))
(extend-protocol IFNExpansion
java.lang.Integer
(expand-all [i] i)
(expand-all-with [i f] i)
java.lang.Long
(expand-all [l] l)
(expand-all-with [l f] l)
java.lang.String
(expand-all [s] s)
(expand-all-with [s f] s)
java.lang.Float
(expand-all [fl] fl)
(expand-all-with [fl f] fl)
java.lang.Double
(expand-all [d] d)
(expand-all-with [d f] d)
;; maps are also functions, so be careful here. MK.
clojure.lang.IPersistentMap
(expand-all [m] (apply-to-values m expand-all))
(expand-all-with [m f] (apply-to-values m (fpartial expand-all-with f)))
clojure.lang.PersistentVector
(expand-all [v] (map expand-all v))
(expand-all-with [v f] (map (fpartial expand-all-with f) v))
;; this distinguishes functions from maps, sets and so on, which are also
;; clojure.lang.AFn subclasses. MK.
clojure.lang.AFunction
(expand-all [f] (f))
(expand-all-with [f expander] (expander f))
Object
(expand-all [x] x)
(expand-all-with [x f] x))

View file

@ -1,11 +1,35 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.internal.pagination)

View file

@ -1,23 +1,48 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "An optional convenience namespaces for applications that heavily use dates and would prefer use JodaTime types
transparently when storing and loading them from MongoDB and serializing to JSON and/or with Clojure reader.
(ns monger.joda-time
"An optional convenience namespaces for applications that heavily use dates and would prefer use JodaTime types
transparently when storing and loading them from MongoDB and serializing to JSON and/or with Clojure reader.
Enables automatic conversion of JodaTime date/time/instant instances to JDK dates (java.util.Date) when documents
are serialized and the other way around when documents are loaded. Extends clojure.data.json/Write-JSON protocol for
JodaTime types.
Enables automatic conversion of JodaTime date/time/instant instances to JDK dates (java.util.Date) when documents
are serialized and the other way around when documents are loaded. Extends clojure.data.json/Write-JSON protocol for
JodaTime types.
To use it, make sure you add dependencies on clj-time (or JodaTime) and clojure.data.json."} monger.joda-time
To use it, make sure you add dependencies on clj-time (or JodaTime) and clojure.data.json."
(:import [org.joda.time DateTime DateTimeZone ReadableInstant]
[org.joda.time.format ISODateTimeFormat])
(:use [monger.conversion]))
(:require [monger.conversion :refer :all]))
;;
;; API
@ -26,6 +51,9 @@
(extend-protocol ConvertToDBObject
org.joda.time.base.AbstractInstant
(to-db-object [^AbstractInstant input]
(to-db-object (.toDate input)))
org.joda.time.base.AbstractPartial
(to-db-object [^AbstractPartial input]
(to-db-object (.toDate input))))
(extend-protocol ConvertFromDBObject
@ -39,31 +67,17 @@
;; Reader extensions
;;
(defmethod print-dup java.util.Date
[^java.util.Date d ^java.io.Writer out]
(.write out
(str "#="
`(java.util.Date. ~(.getYear d)
~(.getMonth d)
~(.getDate d)
~(.getHours d)
~(.getMinutes d)
~(.getSeconds d)))))
(defmethod print-dup org.joda.time.base.AbstractInstant
[^org.joda.time.base.AbstractInstant d out]
(print-dup (.toDate d) out))
(defmethod print-dup org.joda.time.base.AbstractPartial
[^org.joda.time.base.AbstractPartial d out]
(print-dup (.toDate d) out))
;;
;; JSON serialization
;;
(try
;; try to load clojure.data.json. If available, load CLJW Support
;; extensions.
(require 'clojure.data.json)
(require 'clojurewerkz.support.json)
(catch Throwable _
false))
(require 'clojurewerkz.support.json)

View file

@ -1,13 +1,38 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Kept for backwards compatibility. Please use clojurewerkz.support.js from now on."} monger.js
(ns monger.js
"Kept for backwards compatibility. Please use clojurewerkz.support.js from now on."
(:require [clojurewerkz.support.js :as js]))

View file

@ -1,24 +1,116 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.json
"Provides clojure.data.json/Write-JSON protocol extension for MongoDB-specific types, such as
org.bson.types.ObjectId"
(:import org.bson.types.ObjectId
org.bson.types.BSONTimestamp))
;;
;; Implementation
;;
;; copied from clojure.reducers
(defmacro ^:private compile-if
"Evaluate `exp` and if it returns logical true and doesn't error, expand to
`then`. Else expand to `else`.
(compile-if (Class/forName \"java.util.concurrent.ForkJoinTask\")
(do-cool-stuff-with-fork-join)
(fall-back-to-executor-services))"
[exp then else]
(if (try (eval exp)
(catch Throwable _ false))
`(do ~then)
`(do ~else)))
(ns ^{:doc "Provides clojure.data.json/Write-JSON protocol extension for MongoDB-specific types, such as
org.bson.types.ObjectId"}
monger.json
(:import org.bson.types.ObjectId)
(:require [clojure.data.json :as json]
clojurewerkz.support.json))
;;
;; API
;;
(extend-protocol json/Write-JSON
ObjectId
(write-json [^ObjectId object out escape-unicode?]
(json/write-json (.toString object) out escape-unicode?)))
(require 'clojurewerkz.support.json)
;; all this madness would not be necessary if some people cared about backwards
;; compatiblity of the libraries they maintain. Shame on the clojure.data.json maintainer. MK.
(compile-if (and (find-ns 'clojure.data.json)
clojure.data.json/JSONWriter)
(try
(extend-protocol clojure.data.json/JSONWriter
ObjectId
(-write
([^ObjectId object out]
(clojure.data.json/write (.toString object) out))
([^ObjectId object out options]
(clojure.data.json/write (.toString object) out options))))
(extend-protocol clojure.data.json/JSONWriter
BSONTimestamp
(-write
([^BSONTimestamp object out]
(clojure.data.json/write {:time (.getTime object) :inc (.getInc object)} out))
([^BSONTimestamp object out options]
(clojure.data.json/write {:time (.getTime object) :inc (.getInc object)} out options))))
(catch Throwable _
false))
(comment "Nothing to do, clojure.data.json is not available"))
(compile-if (and (find-ns 'clojure.data.json)
clojure.data.json/Write-JSON)
(try
(extend-protocol clojure.data.json/Write-JSON
ObjectId
(write-json [^ObjectId object out escape-unicode?]
(clojure.data.json/write-json (.toString object) out escape-unicode?)))
(catch Throwable _
false))
(comment "Nothing to do, clojure.data.json 0.1.x is not available"))
(try
(require 'cheshire.generate)
(catch Throwable t
false))
(try
(cheshire.generate/add-encoder ObjectId
(fn [^ObjectId oid ^com.fasterxml.jackson.core.json.WriterBasedJsonGenerator generator]
(.writeString generator (.toString oid))))
(cheshire.generate/add-encoder BSONTimestamp
(fn [^BSONTimestamp ts ^com.fasterxml.jackson.core.json.WriterBasedJsonGenerator generator]
(cheshire.generate/encode-map {:time (.getTime ts) :inc (.getInc ts)} generator)))
(catch Throwable t
false))

View file

@ -1,18 +1,42 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Provides vars that represent various MongoDB operators, for example, $gt or $in or $regex.
They can be passed in queries as strings but using vars from this namespace makes the code
a bit cleaner and closer to what you would see in a MongoDB shell query.
(ns monger.operators
"Provides vars that represent various MongoDB operators, for example, $gt or $in or $regex.
They can be passed in queries as strings but using vars from this namespace makes the code
a bit cleaner and closer to what you would see in a MongoDB shell query.
Related documentation guide: http://clojuremongodb.info/articles/querying.html"}
monger.operators)
Related documentation guide: http://clojuremongodb.info/articles/querying.html")
(defmacro ^{:private true} defoperator
[operator]
@ -22,6 +46,8 @@
;; QUERY OPERATORS
;;
(declare $gt $gte $lt $lte $all $in $nin $eq $ne $elemMatch $regex $options)
;; $gt is "greater than" comparator
;; $gte is "greater than or equals" comparator
;; $gt is "less than" comparator
@ -56,10 +82,16 @@
;; (mgcol/find-maps "languages" { :tags { $nin [ "functional" ] } } )
(defoperator $nin)
;; $eq is "equals" comparator
;;
;; EXAMPLES:
;; (monger.collection/find "libraries" { :language { $eq "Clojure" }})
(defoperator $eq)
;; $ne is "non-equals" comparator
;;
;; EXAMPLES:
;; (monger.collection/find "libraries" {$ne { :language "Clojure" }})
;; (monger.collection/find "libraries" { :language { $ne "Clojure" }})
(defoperator $ne)
;; $elemMatch checks if an element in an array matches the specified expression
@ -72,6 +104,37 @@
(defoperator $regex)
(defoperator $options)
;; comment on a query predicate
(declare $comment $explain $hint $maxTimeMS $orderBy $query $returnKey $showDiskLoc $natural)
(defoperator $comment)
(defoperator $explain)
(defoperator $hint)
(defoperator $maxTimeMS)
(defoperator $orderBy)
(defoperator $query)
(defoperator $returnKey)
(defoperator $showDiskLoc)
(defoperator $natural)
;;
;; EVALUATION (QUERY)
;;
(declare $expr $jsonSchema $where $and $or $nor)
(defoperator $expr)
(defoperator $jsonSchema)
;; Matches documents that satisfy a JavaScript expression.
;;
;; EXAMPLES:
;;
;; (monger.collection/find "people" { $where "this.placeOfBirth === this.address.city" })
(defoperator $where)
;;
;; LOGIC OPERATORS
;;
@ -104,6 +167,8 @@
;; ATOMIC MODIFIERS
;;
(declare $inc $mul $set $unset $setOnInsert $rename $push $position $each $addToSet $pop $pull $pullAll $bit $bitsAllClear $bitsAllSet $bitsAnyClear $bitsAnySet $exists $mod $size $type $not)
;; $inc increments one or many fields for the given value, otherwise sets the field to value
;;
;; EXAMPLES:
@ -111,6 +176,8 @@
;; (monger.collection/update "scores" { :_id user-id } { :score 20 :bonus 10 } })
(defoperator $inc)
(defoperator $mul)
;; $set sets an existing (or non-existing) field (or set of fields) to value
;; $set supports all datatypes.
;;
@ -125,6 +192,13 @@
;; (monger.collection/update "things" { :_id oid } { $unset { :weight 1 } })
(defoperator $unset)
;; $setOnInsert assigns values to fields during an upsert only when using the upsert option to the update operation performs an insert.
;; New in version 2.4. http://docs.mongodb.org/manual/reference/operator/setOnInsert/
;;
;; EXAMPLES:
;; (monger.collection/find-and-modify "things" {:_id oid} {$set {:lastseen now} $setOnInsert {:firstseen now}} :upsert true)
(defoperator $setOnInsert)
;; $rename renames a given field
;;
;; EXAMPLES:
@ -138,12 +212,17 @@
;; (mgcol/update "docs" { :_id oid } { $push { :tags "modifiers" } })
(defoperator $push)
;; $pushAll appends each value in value_array to field, if field is an existing array, otherwise sets field to the array value_array
;; if field is not present. If field is present but is not an array, an error condition is raised.
;; $position modifies the behavior of $push per https://docs.mongodb.com/manual/reference/operator/update/position/
(defoperator $position)
;; $each is a modifier for the $push and $addToSet operators for appending multiple values to an array field.
;; Without the $each modifier $push and $addToSet will append an array as a single value.
;; MongoDB 2.4 adds support for the $each modifier to the $push operator.
;; In MongoDB 2.2 the $each modifier can only be used with the $addToSet operator.
;;
;; EXAMPLES:
;; (mgcol/update coll { :_id oid } { $pushAll { :tags ["mongodb" "docs"] } })
(defoperator $pushAll)
;; (mgcol/update coll { :_id oid } { $push { :tags { $each ["mongodb" "docs"] } } })
(defoperator $each)
;; $addToSet Adds value to the array only if its not in the array already, if field is an existing array, otherwise sets field to the
;; array value if field is not present. If field is present but is not an array, an error condition is raised.
@ -171,11 +250,15 @@
;; an error condition is raised.
;;
;; EXAMPLES:
;; (mgcol/update coll { :_id oid } { $pull { :measurements 1.2 } })
;; (mgcol/update coll { :_id oid } { $pull { :measurements { $gte 1.2 } } })
;; (mgcol/update coll { :_id oid } { $pullAll { :measurements 1.2 } })
;; (mgcol/update coll { :_id oid } { $pullAll { :measurements { $gte 1.2 } } })
(defoperator $pullAll)
(defoperator $bit)
(defoperator $bitsAllClear)
(defoperator $bitsAllSet)
(defoperator $bitsAnyClear)
(defoperator $bitsAnySet)
(defoperator $exists)
(defoperator $mod)
@ -185,33 +268,132 @@
;;
;; Aggregation in 2.2
;; Aggregation in 4.2
;;
(declare $addFields $bucket $bucketAuto $collStats $facet $geoNear $graphLookup $indexStats $listSessions $lookup $match $merge $out $planCacheStats $project $redact $replaceRoot $replaceWith $sample $limit $skip $unwind $group $sort $sortByCount $currentOp $listLocalSessions $cmp $min $max $avg $stdDevPop $stdDevSamp $sum $let $first $last $abs $add $ceil $divide $exp $floor $ln $log $log10 $multiply $pow $round $sqrt $subtract $trunc $literal $arrayElemAt $arrayToObject $concatArrays $filter $indexOfArray $isArray $map $objectToArray $range $reduce $reverseArray $zip $mergeObjects $allElementsTrue $anyElementsTrue $setDifference $setEquals $setIntersection $setIsSubset $setUnion $strcasecmp $substr $substrBytes $substrCP $toLower $toString $toUpper $concat $indexOfBytes $indexOfCP $ltrim $regexFind $regexFindAll $regexMatch $rtrim $split $strLenBytes $subLenCP $trim $sin $cos $tan $asin $acos $atan $atan2 $asinh $acosh $atanh $radiansToDegrees $degreesToRadians $convert $toBool $toDecimal $toDouble $toInt $toLong $toObjectId $dayOfMonth $dayOfWeek $dayOfYear $hour $minute $month $second $millisecond $week $year $isoDate $dateFromParts $dateFromString $dateToParts $dateToString $isoDayOfWeek $isoWeek $isoWeekYear $toDate $ifNull $cond $switch)
(defoperator $addFields)
(defoperator $bucket)
(defoperator $bucketAuto)
(defoperator $collStats)
(defoperator $facet)
(defoperator $geoNear)
(defoperator $graphLookup)
(defoperator $indexStats)
(defoperator $listSessions)
(defoperator $lookup)
(defoperator $match)
(defoperator $merge)
(defoperator $out)
(defoperator $planCacheStats)
(defoperator $project)
(defoperator $redact)
(defoperator $replaceRoot)
(defoperator $replaceWith)
(defoperator $sample)
(defoperator $limit)
(defoperator $skip)
(defoperator $unwind)
(defoperator $group)
(defoperator $sort)
(defoperator $sortByCount)
(defoperator $currentOp)
(defoperator $listLocalSessions)
(defoperator $cmp)
(defoperator $min)
(defoperator $max)
(defoperator $avg)
(defoperator $stdDevPop)
(defoperator $stdDevSamp)
(defoperator $sum)
(defoperator $let)
(defoperator $first)
(defoperator $last)
(defoperator $abs)
(defoperator $add)
(defoperator $ceil)
(defoperator $divide)
(defoperator $exp)
(defoperator $floor)
(defoperator $ln)
(defoperator $log)
(defoperator $log10)
(defoperator $multiply)
(defoperator $substract)
(defoperator $pow)
(defoperator $round)
(defoperator $sqrt)
(defoperator $subtract)
(defoperator $trunc)
(defoperator $literal)
(defoperator $arrayElemAt)
(defoperator $arrayToObject)
(defoperator $concatArrays)
(defoperator $filter)
(defoperator $indexOfArray)
(defoperator $isArray)
(defoperator $map)
(defoperator $objectToArray)
(defoperator $range)
(defoperator $reduce)
(defoperator $reverseArray)
(defoperator $zip)
(defoperator $mergeObjects)
(defoperator $allElementsTrue)
(defoperator $anyElementsTrue)
(defoperator $setDifference)
(defoperator $setEquals)
(defoperator $setIntersection)
(defoperator $setIsSubset)
(defoperator $setUnion)
(defoperator $strcasecmp)
(defoperator $substr)
(defoperator $substrBytes)
(defoperator $substrCP)
(defoperator $toLower)
(defoperator $toString)
(defoperator $toUpper)
(defoperator $concat)
(defoperator $indexOfBytes)
(defoperator $indexOfCP)
(defoperator $ltrim)
(defoperator $regexFind)
(defoperator $regexFindAll)
(defoperator $regexMatch)
(defoperator $rtrim)
(defoperator $split)
(defoperator $strLenBytes)
(defoperator $subLenCP)
(defoperator $trim)
(defoperator $sin)
(defoperator $cos)
(defoperator $tan)
(defoperator $asin)
(defoperator $acos)
(defoperator $atan)
(defoperator $atan2)
(defoperator $asinh)
(defoperator $acosh)
(defoperator $atanh)
(defoperator $radiansToDegrees)
(defoperator $degreesToRadians)
(defoperator $convert)
(defoperator $toBool)
(defoperator $toDecimal)
(defoperator $toDouble)
(defoperator $toInt)
(defoperator $toLong)
(defoperator $toObjectId)
(defoperator $dayOfMonth)
(defoperator $dayOfWeek)
@ -220,10 +402,58 @@
(defoperator $minute)
(defoperator $month)
(defoperator $second)
(defoperator $millisecond)
(defoperator $week)
(defoperator $year)
(defoperator $isoDate)
(defoperator $dateFromParts)
(defoperator $dateFromString)
(defoperator $dateToParts)
(defoperator $dateToString)
(defoperator $isoDayOfWeek)
(defoperator $isoWeek)
(defoperator $isoWeekYear)
(defoperator $toDate)
(defoperator $ifNull)
(defoperator $cond)
(defoperator $cond)
(defoperator $switch)
;; Geospatial
(declare $geoWithin $geoIntersects $near $nearSphere $geometry $maxDistance $minDistance $center $centerSphere $box $polygon $slice)
(defoperator $geoWithin)
(defoperator $geoIntersects)
(defoperator $near)
(defoperator $nearSphere)
(defoperator $geometry)
(defoperator $maxDistance)
(defoperator $minDistance)
(defoperator $center)
(defoperator $centerSphere)
(defoperator $box)
(defoperator $polygon)
(defoperator $slice)
;; full text search
(declare $text $meta $search $language $natural $currentDate $isolated $count)
(defoperator $text)
(defoperator $meta)
(defoperator $search)
(defoperator $language)
(defoperator $natural)
;; $currentDate operator sets the value of a field to the current date, either as a Date or a timestamp. The default type is Date.
;;
;; EXAMPLES:
;; (mgcol/update coll { :_id oid } { $currentDate { :lastModified true } })
(defoperator $currentDate)
;; Isolates intermediate multi-document updates from other clients.
;;
;; EXAMPLES:
;; (mgcol/update "libraries" { :language "Clojure", $isolated 1 } { $inc { :popularity 1 } } {:multi true})
(defoperator $isolated)
(defoperator $count)

View file

@ -1,31 +1,56 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Provides an expressive Query DSL that is very close to that in the Mongo shell (within reason).
This is the most flexible and recommended way to query with Monger. Queries can be composed, like in Korma.
(ns monger.query
"Provides an expressive Query DSL that is very close to that in the Mongo shell (within reason).
This is the most flexible and recommended way to query with Monger. Queries can be composed, like in Korma.
Related documentation guide: http://clojuremongodb.info/articles/querying.html"}
monger.query
Related documentation guide: http://clojuremongodb.info/articles/querying.html"
(:refer-clojure :exclude [select find sort])
(:require [monger.core]
[monger.internal pagination])
[monger.internal pagination]
[monger.cursor :as cursor :refer [add-options]]
[monger.conversion :refer :all]
[monger.operators :refer :all])
(:import [com.mongodb DB DBCollection DBObject DBCursor ReadPreference]
[java.util List])
(:use [monger conversion operators]))
[java.util.concurrent TimeUnit]
java.util.List))
;;
;; Implementation
;;
(def ^{:dynamic true} *query-collection*)
;;
;; Cursor/chain methods
;;
@ -41,7 +66,6 @@
;; :skip - Skips the first N results.
;; :limit - Returns a maximum of N results.
;; :batch-size - limits the nubmer of elements returned in one batch.
;; :hint - force Mongo to use a specific index for a query in order to improve performance.
;; :snapshot - sses snapshot mode for the query. Snapshot mode assures no duplicates are returned, or objects missed
;; which were present at both the start and end of the query's execution (if an object is new during the query, or
;; deleted during the query, it may or may not be returned, even with snapshot mode). Note that short query responses
@ -55,7 +79,6 @@
:skip 0
:limit 0
:batch-size 256
:hint nil
:snapshot false
:keywordize-fields true
})
@ -63,19 +86,35 @@
(merge (empty-query) { :collection coll })))
(defn exec
[{ :keys [^DBCollection collection query fields skip limit sort batch-size hint snapshot read-preference keywordize-fields options] :or { limit 0 batch-size 256 skip 0 } }]
(let [cursor (doto (.find collection (to-db-object query) (as-field-selector fields))
(.limit limit)
(.skip skip)
(.sort (to-db-object sort))
(.batchSize batch-size)
(.hint (to-db-object hint)))]
[{:keys [^DBCollection collection
query
fields
skip
limit
sort
batch-size
hint
snapshot
read-preference
keywordize-fields
max-time
options]
:or { limit 0 batch-size 256 skip 0 } }]
(with-open [cursor (doto (.find collection (to-db-object query) (as-field-selector fields))
(.limit limit)
(.skip skip)
(.sort (to-db-object sort))
(.batchSize batch-size))]
(when snapshot
(.snapshot cursor))
(when hint
(.hint cursor (to-db-object hint)))
(when read-preference
(.setReadPreference cursor read-preference))
(when max-time
(.maxTime cursor max-time TimeUnit/MILLISECONDS))
(when options
(.setOptions cursor options))
(add-options cursor options))
(map (fn [x] (from-db-object x keywordize-fields))
cursor)))
@ -119,6 +158,10 @@
[m ^ReadPreference rp]
(merge m { :read-preference rp }))
(defn max-time
[m ^long max-time]
(merge m { :max-time max-time }))
(defn options
[m opts]
(merge m { :options opts }))
@ -132,12 +175,14 @@
(merge m { :limit per-page :skip (monger.internal.pagination/offset-for page per-page) }))
(defmacro with-collection
[^String coll & body]
`(binding [*query-collection* (if (string? ~coll)
(.getCollection ^DB monger.core/*mongodb-database* ~coll)
~coll)]
(let [query# (-> (empty-query *query-collection*) ~@body)]
(exec query#))))
[db coll & body]
`(let [coll# ~coll
^DB db# ~db
db-coll# (if (string? coll#)
(.getCollection db# coll#)
coll#)
query# (-> (empty-query db-coll#) ~@body)]
(exec query#)))
(defmacro partial-query
[& body]

View file

@ -1,9 +1,43 @@
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.ragtime
"Ragtime integration"
(:refer-clojure :exclude [find sort])
(:require [ragtime.core :as ragtime]
(:require [ragtime.protocols :as proto]
[monger.core :as mg]
[monger.collection :as mc])
(:use [monger.query :only [with-collection find sort]])
[monger.collection :as mc]
[monger.query :refer [with-collection find sort]])
(:import java.util.Date
[com.mongodb DB WriteConcern]))
@ -12,23 +46,20 @@
migrations-collection "meta.migrations")
(extend-type com.mongodb.DB
ragtime/Migratable
proto/DataStore
(add-migration-id [db id]
(mc/insert db migrations-collection {:_id id :created_at (Date.)} WriteConcern/FSYNC_SAFE))
(remove-migration-id [db id]
(mc/remove-by-id db migrations-collection id))
(applied-migration-ids [db]
(mg/with-db db
(let [xs (with-collection migrations-collection
(find {})
(sort {:created_at 1}))]
(set (map :_id xs))))))
(let [xs (with-collection db migrations-collection
(find {})
(sort {:created_at 1}))]
(vec (map :_id xs)))))
(defn flush-migrations!
"REMOVES all the information about previously performed migrations"
[db]
(mg/with-db db
(mc/remove migrations-collection)))
[^DB db]
(mc/remove db migrations-collection))

View file

@ -1,78 +1,72 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Provides functions that determine if a query (or other database operation)
was successful or not.
(ns monger.result
"Provides functions that determine if a query (or other database operation)
was successful or not.
Related documentation guides:
Related documentation guides:
* http://clojuremongodb.info/articles/inserting.html
* http://clojuremongodb.info/articles/updating.html
* http://clojuremongodb.info/articles/commands.html
* http://clojuremongodb.info/articles/mapreduce.html"}
monger.result
(:import [com.mongodb DBObject WriteResult MapReduceOutput]
clojure.lang.IPersistentMap)
* http://clojuremongodb.info/articles/inserting.html
* http://clojuremongodb.info/articles/updating.html
* http://clojuremongodb.info/articles/commands.html
* http://clojuremongodb.info/articles/mapreduce.html"
(:import [com.mongodb WriteResult CommandResult])
(:require monger.conversion))
;;
;; Implementation
;;
(defn- okayish?
[value]
(contains? #{true "true" 1 1.0} value))
;;
;; API
;;
(defprotocol MongoCommandResult
(ok? [input] "Returns true if command result is a success")
(has-error? [input] "Returns true if command result indicates an error")
(updated-existing? [input] "Returns true if command result has `updatedExisting` field set to true"))
(extend-protocol MongoCommandResult
DBObject
(ok?
[^DBObject result]
(okayish? (.get result "ok")))
(has-error?
[^DBObject result]
;; yes, this is exactly the logic MongoDB Java driver uses.
(> (count (str (.get result "err"))) 0))
(updated-existing?
[^DBObject result]
(let [v ^Boolean (.get result "updatedExisting")]
(and v (Boolean/valueOf v))))
(defprotocol WriteResultPredicates
(acknowledged? [input] "Returns true if write result is a success")
(updated-existing? [input] "Returns true if write result has updated an existing document"))
(extend-protocol WriteResultPredicates
WriteResult
(ok?
(acknowledged?
[^WriteResult result]
(and (not (nil? result)) (ok? (.getLastError result))))
(has-error?
[^WriteResult result]
(has-error? (.getLastError result)))
(.wasAcknowledged result))
(updated-existing?
[^WriteResult result]
(updated-existing? (.getLastError result)))
(.isUpdateOfExisting result))
MapReduceOutput
(ok?
[^MapReduceOutput result]
(ok? ^DBObject (.getRaw result)))
CommandResult
(acknowledged?
[^CommandResult result]
(.ok result)))
IPersistentMap
(ok?
[^IPersistentMap m]
(okayish? (or (get m :ok)
(get m "ok")))))
(defn affected-count
"Get the number of documents affected"
[^WriteResult result]
(.getN result))

View file

@ -1,8 +1,43 @@
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns monger.ring.session-store
(:require [ring.middleware.session.store :as ringstore]
[monger.collection :as mc])
(:use monger.conversion)
[monger.collection :as mc]
[monger.core :as mg]
[monger.conversion :refer :all])
(:import [java.util UUID Date]
[com.mongodb DB]
ring.middleware.session.store.SessionStore))
;;
@ -23,10 +58,10 @@
;; data structure Clojure reader can serialize and read but won't make the data useful to applications
;; in other languages.
(defrecord ClojureReaderBasedMongoDBSessionStore [^String collection-name])
(defrecord ClojureReaderBasedMongoDBSessionStore [^DB db ^String collection-name])
(defmethod print-dup java.util.Date
[d out]
[^java.util.Date d ^java.io.Writer out]
(.write out
(str "#="
`(java.util.Date. ~(.getYear d)
@ -37,7 +72,7 @@
~(.getSeconds d)))))
(defmethod print-dup org.bson.types.ObjectId
[oid out]
[oid ^java.io.Writer out]
(.write out
(str "#="
`(org.bson.types.ObjectId. ~(str oid)))))
@ -48,7 +83,7 @@
(read-session [store key]
(if key
(if-let [m (mc/find-one-as-map (.collection-name store) {:_id key})]
(if-let [m (mc/find-one-as-map (.db store) (.collection-name store) {:_id key})]
(read-string (:value m))
{})
{}))
@ -58,47 +93,43 @@
key (or key (str (UUID/randomUUID)))
value (binding [*print-dup* true]
(pr-str (assoc data :_id key)))]
(mc/save (.collection-name store) {:_id key :value value :date date})
(mc/save (.db store) (.collection-name store) {:_id key :value value :date date})
key))
(delete-session [store key]
(mc/remove-by-id (.collection-name store) key)
(mc/remove-by-id (.db store) (.collection-name store) key)
nil))
(defn session-store
([]
(ClojureReaderBasedMongoDBSessionStore. default-session-store-collection))
([^String s]
(ClojureReaderBasedMongoDBSessionStore. s)))
[^DB db ^String s]
(ClojureReaderBasedMongoDBSessionStore. db s))
;; this session store won't store namespaced keywords correctly but stores results in a way
;; that applications in other languages can read. DO NOT use it with Friend.
(defrecord MongoDBSessionStore [^String collection-name])
(defrecord MongoDBSessionStore [^DB db ^String collection-name])
(extend-protocol ringstore/SessionStore
MongoDBSessionStore
(read-session [store key]
(if-let [m (and key
(mc/find-one-as-map (.collection-name store) {:_id key}))]
(mc/find-one-as-map (.db store) (.collection-name store) {:_id key}))]
m
{}))
(write-session [store key data]
(let [key (or key (str (UUID/randomUUID)))]
(mc/save (.collection-name store) (assoc data :date (Date.) :_id key))
(mc/save (.db store) (.collection-name store) (assoc data :date (Date.) :_id key))
key))
(delete-session [store key]
(mc/remove-by-id (.collection-name store) key)
(mc/remove-by-id (.db store) (.collection-name store) key)
nil))
(defn monger-store
([]
(MongoDBSessionStore. default-session-store-collection))
([^String s]
(MongoDBSessionStore. s)))
[^DB db ^String s]
(MongoDBSessionStore. db s))

View file

@ -1,147 +0,0 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
(ns ^{:doc "Monger TestKit is an experiment that turned out to be partially successful but partially need to be
rethough, redesigned, integrated with MongoDB DB references and simply reimplemented from the ground up
one more time. For this exact reason, there is no documentation guide on it.
Please keep this in mind if you are considering using it."}
monger.testkit
(:require [monger.collection :as mc]
[monger.result :as mr])
(:use [monger.internal.fn :only (expand-all expand-all-with) :as fntools])
(:import org.bson.types.ObjectId))
;;
;; API
;;
(defmacro defcleaner
"Defines a fixture function that removes all documents from a collection. If collection is not specified,
a conventionally named var will be used. Supposed to be used with clojure.test/use-fixtures but may
be useful on its own.
Examples:
(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))))
(def factories (atom {}))
(def defaults (atom {}))
(def last-oids (atom {}))
(defn defaults-for
[f-group & { :as attributes }]
(swap! defaults (fn [v]
(assoc v (name f-group) attributes))))
(defn factory
[f-group f-name & { :as attributes }]
(swap! factories (fn [a]
(assoc-in a [(name f-group) (name f-name)] attributes))))
(declare build seed remember-oid)
(defn- expand-associate-for-building
[f]
(let [mt (meta f)
[f-group f-name] (f)]
(:_id (build f-group f-name))))
(defn- expand-for-building
"Expands functions, treating those with association metadata (see `parent-id` for example) specially"
[f]
(let [mt (meta f)]
(if (:associate-gen mt)
(expand-associate-for-building f)
(f))))
(defn- expand-associate-for-seeding
[f]
(let [mt (meta f)
[f-group f-name] (f)]
(:_id (seed f-group f-name))))
(defn- expand-for-seeding
"Expands functions, treating those with association metadata (see `parent-id` for example) specially,
making sure parent documents are persisted first"
[f]
(let [mt (meta f)]
(if (:associate-gen mt)
(expand-associate-for-seeding f)
(f))))
(defn build
"Generates a new document and returns it.
Unless _id field is defined by the factory, it is generated."
[f-group f-name & { :as overrides }]
(let [d (@defaults (name f-group))
attributes (get-in @factories [(name f-group) (name f-name)])
merged (merge { :_id (ObjectId.) } d attributes overrides)]
(expand-all-with merged expand-for-building)))
(defn seed
"Generates and inserts a new document, then returns it.
Unless _id field is defined by the factory, it is generated."
[f-group f-name & { :as overrides }]
(io!
(let [d (@defaults (name f-group))
attributes (get-in @factories [(name f-group) (name f-name)])
merged (merge { :_id (ObjectId.) } d attributes overrides)
expanded (expand-all-with merged expand-for-seeding)]
(assert (mr/ok? (mc/insert f-group expanded)))
(remember-oid f-group f-name (:_id expanded))
expanded)))
(defn seed-all
"Seeds all fixtures in the given collection"
[f-group]
(io!
(let [xs (vec (keys (get @factories f-group)))]
(doseq [f-name xs]
(seed f-group f-name)))))
(defn embedded-doc
[f-group f-name & { :as overrides }]
(fn []
(apply build f-group f-name (flatten (vec overrides)))))
(defn parent-id
[f-group f-name]
(with-meta (fn []
[f-group f-name]) { :associate-gen true :parent-gen true }))
(defn- remember-oid
[f-group f-name oid]
(swap! last-oids (fn [a]
(assoc-in a [(name f-group) (name f-name)] oid))))
(defn last-oid-of
"Returns last object id of a document inserted using given factory"
[f-group f-name]
(get-in @last-oids [(name f-group) (name f-name)]))
(def ^{ :doc "Returns a new object id. Generates it if needed, otherwise returns a cached version.
Useful for defining referenced associations between fixture documents." }
memoized-oid (memoize (fn [f-group f-name]
(ObjectId.))))

View file

@ -1,19 +1,45 @@
;; Copyright (c) 2011-2012 Michael S. Klishin
;; This source code is dual-licensed under the Apache License, version
;; 2.0, and the Eclipse Public License, version 1.0.
;;
;; The use and distribution terms for this software are covered by the
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this distribution.
;; By using this software in any fashion, you are agreeing to be bound by
;; the terms of this license.
;; You must not remove this notice, or any other, from this software.
;; The APL v2.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; ----------------------------------------------------------------------------------
;;
;; The EPL v1.0:
;;
;; ----------------------------------------------------------------------------------
;; Copyright (c) 2011-2018 Michael S. Klishin, Alex Petrov, and the ClojureWerkz Team.
;; All rights reserved.
;;
;; This program and the accompanying materials are made available under the terms of
;; the Eclipse Public License Version 1.0,
;; which accompanies this distribution and is available at
;; http://www.eclipse.org/legal/epl-v10.html.
;; ----------------------------------------------------------------------------------
(ns ^{:doc "Provides various utility functions, primarily for working with document ids."} monger.util
(:refer-clojure :exclude [random-uuid])
(:import java.security.SecureRandom
java.math.BigInteger
org.bson.types.ObjectId
com.mongodb.DBObject
clojure.lang.IPersistentMap
java.util.Map))
java.util.Map)
(:refer-clojure :exclude [random-uuid]))
;;
;; API
@ -30,9 +56,11 @@
(.toString (new BigInteger n (SecureRandom.)) num-base))
(defn ^ObjectId object-id
"Returns a new BSON object id"
[]
(ObjectId.))
"Returns a new BSON object id, or converts str to BSON object id"
([]
(ObjectId.))
([^String s]
(ObjectId. s)))
(defprotocol GetDocumentId
(get-id [input] "Returns document id"))
@ -47,3 +75,8 @@
(get-id
[^IPersistentMap object]
(or (:_id object) (object "_id"))))
(defn into-array-list
"Coerce a j.u.Collection into a j.u.ArrayList."
^java.util.ArrayList [^java.util.Collection coll]
(java.util.ArrayList. coll))

View file

@ -1,44 +0,0 @@
package com.novemberain.monger;
import clojure.lang.IDeref;
import com.mongodb.DB;
import com.mongodb.DBObject;
import org.bson.BSONObject;
/**
* Exactly as com.mongodb.DBRef but also implements Clojure IDeref for @dereferencing
*/
public class DBRef extends com.mongodb.DBRef implements IDeref {
/**
* Creates a DBRef
* @param db the database
* @param o a BSON object representing the reference
*/
public DBRef(DB db, BSONObject o) {
super(db , o.get("$ref").toString(), o.get("$id"));
}
/**
* Creates a DBRef
* @param db the database
* @param ns the namespace where the object is stored
* @param id the object id
*/
public DBRef(DB db, String ns, Object id) {
super(db, ns, id);
}
/**
* Creates a DBRef from a com.mongodb.DBRef instance.
* @param source The original reference MongoDB Java driver uses
*/
public DBRef(com.mongodb.DBRef source) {
this(source.getDB(), source.getRef(), source.getId());
}
@Override
public DBObject deref() {
return this.fetch();
}
}

View file

@ -1,69 +1,136 @@
(ns monger.test.aggregation-framework-test
(:require monger.core [monger.collection :as mc]
[monger.test.helper :as helper])
(:use clojure.test
monger.operators
monger.test.fixtures))
(:require [monger.core :as mg]
[monger.collection :as mc]
[clojure.test :refer :all]
[monger.operators :refer :all]))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
coll "docs"]
(defn purge-collections
[f]
(mc/purge-many db [coll])
(f)
(mc/purge-many db [coll]))
(use-fixtures :each purge-collections)
(deftest test-basic-single-stage-$project-aggregation-no-keywordize
(let [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 }]
expected #{{"quantity" 1 "state" "CA"}
{"quantity" 2 "state" "NY"}
{"quantity" 1 "state" "NY"}
{"quantity" 2 "state" "IL"}
{"quantity" 2 "state" "CA"}
{"quantity" 3 "state" "IL"}}]
(mc/insert-batch db coll batch)
(is (= 6 (mc/count db coll)))
(let [result (->>
(mc/aggregate db coll [{$project {"state" 1 "quantity" 1}}] :keywordize false)
(map #(select-keys % ["state" "quantity"]))
(set))]
(is (= expected result)))))
(deftest test-basic-single-stage-$project-aggregation
(let [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 }]
expected #{{:quantity 1 :state "CA"}
{:quantity 2 :state "NY"}
{:quantity 1 :state "NY"}
{:quantity 2 :state "IL"}
{:quantity 2 :state "CA"}
{:quantity 3 :state "IL"}}]
(mc/insert-batch db coll batch)
(is (= 6 (mc/count db coll)))
(let [result (set (map #(select-keys % [:state :quantity])
(mc/aggregate db coll [{$project {:state 1 :quantity 1}}])))]
(is (= expected result)))))
(helper/connect!)
(use-fixtures :each purge-docs)
(deftest ^{:edge-features true} test-basic-single-stage-$project-aggregation
(let [collection "docs"
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 }]
expected #{{:quantity 1 :state "CA"}
{:quantity 2 :state "NY"}
{:quantity 1 :state "NY"}
{:quantity 2 :state "IL"}
{:quantity 2 :state "CA"}
{:quantity 3 :state "IL"}}]
(mc/insert-batch collection batch)
(is (= 6 (mc/count collection)))
(let [result (set (map #(select-keys % [:state :quantity])
(mc/aggregate "docs" [{$project {:state 1 :quantity 1}}])))]
(is (= expected result)))))
(deftest test-basic-projection-with-multiplication
(let [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 }]
expected #{{:_id "NY" :subtotal 398.0}
{:_id "NY" :subtotal 299.0}
{:_id "IL" :subtotal 23.0}
{:_id "CA" :subtotal 5.9}
{:_id "IL" :subtotal 16.5}
{:_id "CA" :subtotal 199.0}}]
(mc/insert-batch db coll batch)
(let [result (set (mc/aggregate db coll [{$project {:subtotal {$multiply ["$quantity", "$price"]}
:_id "$state"}}]))]
(is (= expected result)))))
(deftest ^{:edge-features true} test-basic-projection-with-multiplication
(let [collection "docs"
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 }]
expected #{{:_id "NY" :subtotal 398.0}
{:_id "NY" :subtotal 299.0}
{:_id "IL" :subtotal 23.0}
{:_id "CA" :subtotal 5.9}
{:_id "IL" :subtotal 16.5}
{:_id "CA" :subtotal 199.0}}]
(mc/insert-batch collection batch)
(let [result (set (mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
:_id "$state"}}]))]
(is (= expected result)))))
(deftest test-basic-total-aggregation
(let [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 }]
expected #{{:_id "CA" :total 204.9} {:_id "IL" :total 39.5} {:_id "NY" :total 697.0}}]
(mc/insert-batch db coll batch)
(let [result (set (mc/aggregate db coll [{$project {:subtotal {$multiply ["$quantity", "$price"]}
:_id 1
:state 1}}
{$group {:_id "$state"
:total {$sum "$subtotal"}}}]))]
(is (= expected result)))))
(deftest ^{:edge-features true} test-basic-total-aggregation
(let [collection "docs"
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 }]
expected #{{:_id "CA" :total 204.9} {:_id "IL" :total 39.5} {:_id "NY" :total 697.0}}]
(mc/insert-batch collection batch)
(let [result (set (mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
:_id 1
:state 1}}
{$group {:_id "$state"
:total {$sum "$subtotal"}}}]))]
(is (= expected result)))))
(deftest test-$first-aggregation-operator
(let [batch [{:state "CA"}
{:state "IL"}]
expected "CA"]
(mc/insert-batch db coll batch)
(let [result (:state (first (mc/aggregate db coll [{$group {:_id 1 :state {$first "$state"}}}])))]
(is (= expected result)))))
(deftest test-$last-aggregation-operator
(let [batch [{:state "CA"}
{:state "IL"}]
expected "IL"]
(mc/insert-batch db coll batch)
(let [result (:state (first (mc/aggregate db coll [{$group {:_id 1 :state {$last "$state"}}}])))]
(is (= expected result)))))
(deftest test-cursor-aggregation
(let [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 }]
expected #{{:quantity 1 :state "CA"}
{:quantity 2 :state "NY"}
{:quantity 1 :state "NY"}
{:quantity 2 :state "IL"}
{:quantity 2 :state "CA"}
{:quantity 3 :state "IL"}}]
(mc/insert-batch db coll batch)
(is (= 6 (mc/count db coll)))
(let [result (set (map #(select-keys % [:state :quantity])
(mc/aggregate db coll [{$project {:state 1 :quantity 1}}] :cursor {:batch-size 10})))]
(is (= expected result)))))
(deftest test-explain-aggregate
(let [batch [{:state "CA" :price 100}
{:state "CA" :price 10}
{:state "IL" :price 50}]]
(mc/insert-batch db coll batch)
(let [result (mc/explain-aggregate db coll [{$match {:state "CA"}}])]
(is (:ok result))))))

View file

@ -1,348 +1,461 @@
(set! *warn-on-reflection* true)
(ns monger.test.atomic-modifiers-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure]
[org.bson.types ObjectId]
[java.util Date])
(:require [monger core util]
[monger.collection :as mgcol]
[monger.result :as mgres]
[monger.test.helper :as helper])
(:use [clojure.test]
[monger.operators]
[monger.test.fixtures]))
(helper/connect!)
(use-fixtures :each purge-docs purge-things purge-scores)
;;
;; $inc
;;
(deftest increment-a-single-existing-field-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :username "l33r0y" :score 100 })
(mgcol/update coll { :_id oid } { $inc { :score 20 } })
(is (= 120 (:score (mgcol/find-map-by-id coll oid))))))
(deftest set-a-single-non-existing-field-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :username "l33r0y" })
(mgcol/update coll { :_id oid } { $inc { :score 30 } })
(is (= 30 (:score (mgcol/find-map-by-id coll oid))))))
(deftest increment-multiple-existing-fields-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :username "l33r0y" :score 100 :bonus 0 })
(mgcol/update coll { :_id oid } {$inc { :score 20 :bonus 10 } })
(is (= { :_id oid :score 120 :bonus 10 :username "l33r0y" } (mgcol/find-map-by-id coll oid)))))
(deftest increment-and-set-multiple-existing-fields-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :username "l33r0y" :score 100 })
(mgcol/update coll { :_id oid } { $inc { :score 20 :bonus 10 } })
(is (= { :_id oid :score 120 :bonus 10 :username "l33r0y" } (mgcol/find-map-by-id coll oid)))))
;;
;; $set
;;
(deftest update-a-single-existing-field-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :weight 10.0 })
(mgcol/update coll { :_id oid } { $set { :weight 20.5 } })
(is (= 20.5 (:weight (mgcol/find-map-by-id coll oid [:weight]))))))
(deftest set-a-single-non-existing-field-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :weight 10.0 })
(mgcol/update coll { :_id oid } { $set { :height 17.2 } })
(is (= 17.2 (:height (mgcol/find-map-by-id coll oid [:height]))))))
(deftest update-multiple-existing-fields-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :weight 10.0 :height 15.2 })
(mgcol/update coll { :_id oid } { $set { :weight 20.5 :height 25.6 } })
(is (= { :_id oid :weight 20.5 :height 25.6 } (mgcol/find-map-by-id coll oid [:weight :height])))))
(deftest update-and-set-multiple-fields-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :weight 10.0 })
(mgcol/update coll { :_id oid } {$set { :weight 20.5 :height 25.6 } })
(is (= { :_id oid :weight 20.5 :height 25.6 } (mgcol/find-map-by-id coll oid [:weight :height])))))
;;
;; $unset
;;
(deftest unset-a-single-existing-field-using-$unset-modifier
(let [coll "docs"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :title "Document 1" :published true })
(mgcol/update coll { :_id oid } { $unset { :published 1 } })
(is (= { :_id oid :title "Document 1" } (mgcol/find-map-by-id coll oid)))))
(deftest unset-multiple-existing-fields-using-$unset-modifier
(let [coll "docs"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :title "Document 1" :published true :featured true })
(mgcol/update coll { :_id oid } { $unset { :published 1 :featured true } })
(is (= { :_id oid :title "Document 1" } (mgcol/find-map-by-id coll oid)))))
(deftest unsetting-an-unexisting-field-using-$unset-modifier-is-not-considered-an-issue
(let [coll "docs"
oid (ObjectId.)]
(mgcol/insert coll { :_id oid :title "Document 1" :published true })
(is (mgres/ok? (mgcol/update coll { :_id oid } { $unset { :published 1 :featured true } })))
(is (= { :_id oid :title "Document 1" } (mgcol/find-map-by-id coll oid)))))
;;
;; $push
;;
(deftest initialize-an-array-using-$push-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mgcol/insert coll { :_id oid :title title })
(mgcol/update coll { :_id oid } { $push { :tags "modifiers" } })
(is (= { :_id oid :title title :tags ["modifiers"] } (mgcol/find-map-by-id coll oid)))))
(deftest add-value-to-an-existing-array-using-$push-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb"] })
(mgcol/update coll { :_id oid } { $push { :tags "modifiers" } })
(is (= { :_id oid :title title :tags ["mongodb" "modifiers"] } (mgcol/find-map-by-id 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 [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb"] })
(mgcol/update coll { :_id oid } { $push { :tags ["modifiers" "operators"] } })
(is (= { :_id oid :title title :tags ["mongodb" ["modifiers" "operators"]] } (mgcol/find-map-by-id coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$push-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb"] })
(mgcol/update coll { :_id oid } { $push { :tags "modifiers" } })
(mgcol/update coll { :_id oid } { $push { :tags "modifiers" } })
(is (= { :_id oid :title title :tags ["mongodb" "modifiers" "modifiers"] } (mgcol/find-map-by-id coll oid)))))
;;
;; $pushAll
;;
(deftest initialize-an-array-using-$pushAll-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pushAll modifier appends multiple values to field"]
(mgcol/insert coll { :_id oid :title title })
(mgcol/update coll { :_id oid } { $pushAll { :tags ["mongodb" "docs"] } })
(is (= { :_id oid :title title :tags ["mongodb" "docs"] } (mgcol/find-map-by-id coll oid)))))
(deftest add-value-to-an-existing-array-using-$pushAll-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pushAll modifier appends multiple values to field"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb"] })
(mgcol/update coll { :_id oid } { $pushAll { :tags ["modifiers" "docs"] } })
(is (= { :_id oid :title title :tags ["mongodb" "modifiers" "docs"] } (mgcol/find-map-by-id coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$pushAll-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pushAll modifier appends multiple values to field"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb" "docs"] })
(mgcol/update coll { :_id oid } { $pushAll { :tags ["modifiers" "docs"] } })
(is (= { :_id oid :title title :tags ["mongodb" "docs" "modifiers" "docs"] } (mgcol/find-map-by-id coll oid)))))
;;
;; $addToSet
;;
(deftest initialize-an-array-using-$addToSet-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet modifier appends value to field unless it is already there"]
(mgcol/insert coll { :_id oid :title title })
(mgcol/update coll { :_id oid } { $addToSet { :tags "modifiers" } })
(is (= { :_id oid :title title :tags ["modifiers"] } (mgcol/find-map-by-id coll oid)))))
(deftest add-value-to-an-existing-array-using-$addToSet-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet modifier appends value to field unless it is already there"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb"] })
(mgcol/update coll { :_id oid } { $addToSet { :tags "modifiers" } })
(is (= { :_id oid :title title :tags ["mongodb" "modifiers"] } (mgcol/find-map-by-id coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$addToSet-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet modifier appends value to field unless it is already there"]
(mgcol/insert coll { :_id oid :title title :tags ["mongodb"] })
(mgcol/update coll { :_id oid } { $addToSet { :tags "modifiers" } })
(mgcol/update coll { :_id oid } { $addToSet { :tags "modifiers" } })
(is (= { :_id oid :title title :tags ["mongodb" "modifiers"] } (mgcol/find-map-by-id coll oid)))))
;;
;; $pop
;;
(deftest pop-last-value-in-the-array-using-$pop-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pop modifier removes last or first value in the array"]
(mgcol/insert coll { :_id oid :title title :tags ["products" "apple" "reviews"] })
(mgcol/update coll { :_id oid } { $pop { :tags 1 } })
(is (= { :_id oid :title title :tags ["products" "apple"] } (mgcol/find-map-by-id coll oid)))))
(deftest unshift-first-value-in-the-array-using-$pop-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pop modifier removes last or first value in the array"]
(mgcol/insert coll { :_id oid :title title :tags ["products" "apple" "reviews"] })
(mgcol/update coll { :_id oid } { $pop { :tags -1 } })
(is (= { :_id oid :title title :tags ["apple" "reviews"] } (mgcol/find-map-by-id coll oid)))))
(deftest pop-last-values-from-multiple-arrays-using-$pop-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pop modifier removes last or first value in the array"]
(mgcol/insert coll { :_id oid :title title :tags ["products" "apple" "reviews"] :categories ["apple" "reviews" "drafts"] })
(mgcol/update coll { :_id oid } { $pop { :tags 1 :categories 1 } })
(is (= { :_id oid :title title :tags ["products" "apple"] :categories ["apple" "reviews"] } (mgcol/find-map-by-id coll oid)))))
;;
;; $pull
;;
(deftest remove-all-value-entries-from-array-using-$pull-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pull modifier removes all value entries in the array"]
(mgcol/insert 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 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 coll oid)))))
(deftest remove-all-value-entries-from-array-using-$pull-modifier-based-on-a-condition
(let [coll "docs"
oid (ObjectId.)
title "$pull modifier removes all value entries in the array"]
(mgcol/insert 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 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 coll oid)))))
;;
;; $pullAll
;;
(deftest remove-all-value-entries-from-array-using-$pullAll-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pullAll modifier removes entries of multiple values in the array"]
(mgcol/insert 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 coll { :_id oid } { $pullAll { :measurements [1.0 1.1 1.2] } })
(is (= { :_id oid :title title :measurements [1.3] } (mgcol/find-map-by-id coll oid)))))
;;
;; $rename
;;
(deftest rename-a-single-field-using-$rename-modifier
(let [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 coll { :_id oid :title title :measurements v })
(mgcol/update coll { :_id oid } { $rename { :measurements "results" } })
(is (= { :_id oid :title title :results v } (mgcol/find-map-by-id coll oid)))))
;;
;; find-and-modify
;;
(deftest find-and-modify-a-single-document
(let [coll "docs"
oid (ObjectId.)
doc {:_id oid :name "Sophie Bangs" :level 42}
conditions {:name "Sophie Bangs"}
update {$inc {:level 1}}]
(mgcol/insert coll doc)
(let [res (mgcol/find-and-modify coll conditions update :return-new true)]
(is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 43})))))
(deftest find-and-modify-remove-a-document
(let [coll "docs"
oid (ObjectId.)
doc {:_id oid :name "Sophie Bangs" :level 42}
conditions {:name "Sophie Bangs"}]
(mgcol/insert coll doc)
(let [res (mgcol/find-and-modify coll conditions {} :remove true)]
(is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42}))
(is (empty? (mgcol/find-maps coll conditions))))))
(deftest find-and-modify-upsert-a-document
(testing "case 1"
(:import [com.mongodb WriteResult WriteConcern DBObject]
org.bson.types.ObjectId
java.util.Date)
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.result :refer [acknowledged?]]
[clojure.test :refer :all]
[monger.operators :refer :all]))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-collections
[f]
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "scores")
(f)
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "scores"))
(use-fixtures :each purge-collections)
;;
;; $inc
;;
(deftest increment-a-single-existing-field-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :username "l33r0y" :score 100})
(mc/update db coll {:_id oid} {$inc {:score 20}})
(is (= 120 (:score (mc/find-map-by-id db coll oid))))))
(deftest set-a-single-non-existing-field-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :username "l33r0y"})
(mc/update db coll {:_id oid} {$inc {:score 30}})
(is (= 30 (:score (mc/find-map-by-id db coll oid))))))
(deftest increment-multiple-existing-fields-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :username "l33r0y" :score 100 :bonus 0})
(mc/update db coll {:_id oid} {$inc {:score 20 :bonus 10}})
(is (= {:_id oid :score 120 :bonus 10 :username "l33r0y"}
(mc/find-map-by-id db coll oid)))))
(deftest increment-and-set-multiple-existing-fields-using-$inc-modifier
(let [coll "scores"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :username "l33r0y" :score 100})
(mc/update db coll {:_id oid} {$inc {:score 20 :bonus 10}})
(is (= {:_id oid :score 120 :bonus 10 :username "l33r0y"}
(mc/find-map-by-id db coll oid)))))
;;
;; $set
;;
(deftest update-a-single-existing-field-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :weight 10.0})
(mc/update db coll {:_id oid} {$set {:weight 20.5}})
(is (= 20.5 (:weight (mc/find-map-by-id db coll oid [:weight]))))))
(deftest set-a-single-non-existing-field-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :weight 10.0})
(mc/update db coll {:_id oid} {$set {:height 17.2}})
(is (= 17.2 (:height (mc/find-map-by-id db coll oid [:height]))))))
(deftest update-multiple-existing-fields-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :weight 10.0 :height 15.2})
(mc/update db coll {:_id oid} {$set {:weight 20.5 :height 25.6}})
(is (= {:_id oid :weight 20.5 :height 25.6}
(mc/find-map-by-id db coll oid [:weight :height])))))
(deftest update-and-set-multiple-fields-using-$set-modifier
(let [coll "things"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :weight 10.0})
(mc/update db coll {:_id oid} {$set {:weight 20.5 :height 25.6}})
(is (= {:_id oid :weight 20.5 :height 25.6}
(mc/find-map-by-id db coll oid [:weight :height])))))
;;
;; $unset
;;
(deftest unset-a-single-existing-field-using-$unset-modifier
(let [coll "docs"
oid (ObjectId.)
doc {:_id oid :name "Sophie Bangs" :level 42}]
(let [res (mgcol/find-and-modify coll doc doc :upsert true)]
(is (empty? res))
(is (select-keys (mgcol/find-map-by-id coll oid) [:name :level]) (dissoc doc :_id)))))
(testing "case 2"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :title "Document 1" :published true})
(mc/update db coll {:_id oid} {$unset {:published 1}})
(is (= {:_id oid :title "Document 1"}
(mc/find-map-by-id db coll oid)))))
(deftest unset-multiple-existing-fields-using-$unset-modifier
(let [coll "docs"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :title "Document 1" :published true :featured true})
(mc/update db coll {:_id oid} {$unset {:published 1 :featured true}})
(is (= {:_id oid :title "Document 1"}
(mc/find-map-by-id db coll oid)))))
(deftest unsetting-an-unexisting-field-using-$unset-modifier-is-not-considered-an-issue
(let [coll "docs"
oid (ObjectId.)]
(mc/insert db coll {:_id oid :title "Document 1" :published true})
(is (acknowledged? (mc/update db coll {:_id oid} {$unset {:published 1 :featured true}})))
(is (= {:_id oid :title "Document 1"}
(mc/find-map-by-id db coll oid)))))
;;
;; $setOnInsert
;;
(deftest setOnInsert-in-upsert-for-non-existing-document
(let [coll "docs"
now 456
oid (ObjectId.)]
(mc/find-and-modify db coll {:_id oid} {$set {:lastseen now} $setOnInsert {:firstseen now}} {:upsert true})
(is (= {:_id oid :lastseen now :firstseen now}
(mc/find-map-by-id db coll oid)))))
(deftest setOnInsert-in-upsert-for-existing-document
(let [coll "docs"
before 123
now 456
oid (ObjectId.)]
(mc/insert db coll {:_id oid :firstseen before :lastseen before})
(mc/find-and-modify db coll {:_id oid} {$set {:lastseen now} $setOnInsert {:firstseen now}} {:upsert true})
(is (= {:_id oid :lastseen now :firstseen before}
(mc/find-map-by-id db coll oid)))))
;;
;; $push
;;
(deftest initialize-an-array-using-$push-modifier
(let [coll "docs"
query {:name "Sophie Bangs"}
doc (merge query {:level 42})]
(let [res (mgcol/find-and-modify coll query doc :upsert true :return-new true)]
(is (:_id res))
(is (select-keys (mgcol/find-map-by-id coll (:_id res)) [:name :level]) doc)))))
oid (ObjectId.)
title "$push modifier appends value to field"]
(mc/insert db coll {:_id oid :title title})
(mc/update db coll {:_id oid} {$push {:tags "modifiers"}})
(is (= {:_id oid :title title :tags ["modifiers"]}
(mc/find-map-by-id db coll oid)))))
(deftest add-value-to-an-existing-array-using-$push-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$push {:tags "modifiers"}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers"]}
(mc/find-map-by-id db coll oid)))))
(deftest find-and-modify-after-sort
(let [coll "docs"
oid (ObjectId.)
oid2 (ObjectId.)
doc {:name "Sophie Bangs"}
doc1 (assoc doc :_id oid :level 42)
doc2 (assoc doc :_id oid2 :level 0)]
(mgcol/insert-batch coll [doc1 doc2])
(let [res (mgcol/find-and-modify coll doc {$inc {:level 1}} :sort {:level -1})]
(is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42})))))
;; 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 $push with $each instead of $push. MK.
(deftest add-array-value-to-an-existing-array-using-$push-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$push {:tags ["modifiers" "operators"]}})
(is (= {:_id oid :title title :tags ["mongodb" ["modifiers" "operators"]]}
(mc/find-map-by-id db coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$push-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push modifier appends value to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$push {:tags "modifiers"}})
(mc/update db coll {:_id oid} {$push {:tags "modifiers"}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers" "modifiers"]}
(mc/find-map-by-id db coll oid)))))
;;
;; $push $each
;;
(deftest initialize-an-array-using-$push-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push with $each modifier appends multiple values to field"]
(mc/insert db coll {:_id oid :title title})
(mc/update db coll {:_id oid} {$push {:tags {$each ["mongodb" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "docs"]}
(mc/find-map-by-id db coll oid)))))
(deftest add-values-to-an-existing-array-using-$push-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push with $each modifier appends multiple values to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$push {:tags {$each ["modifiers" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers" "docs"]}
(mc/find-map-by-id db coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$push-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$push with $each modifier appends multiple values to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb" "docs"]})
(mc/update db coll {:_id oid} {$push {:tags {$each ["modifiers" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "docs" "modifiers" "docs"]}
(mc/find-map-by-id db coll oid)))))
;;
;; $push + $each (formerly $pushAll)
;;
(deftest initialize-an-array-using-$push-and-$each-modifiers
(let [coll "docs"
oid (ObjectId.)
title "$pushAll modifier appends multiple values to field"]
(mc/insert db coll {:_id oid :title title})
(mc/update db coll {:_id oid} {$push {:tags {$each ["mongodb" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "docs"]}
(mc/find-map-by-id db coll oid)))))
(deftest add-value-to-an-existing-array-using-$push-and-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pushAll modifier appends multiple values to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$push {:tags {$each ["modifiers" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers" "docs"]}
(mc/find-map-by-id db coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$push-and-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pushAll modifier appends multiple values to field"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb" "docs"]})
(mc/update db coll {:_id oid} {$push {:tags {$each ["modifiers" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "docs" "modifiers" "docs"]}
(mc/find-map-by-id db coll oid)))))
;;
;; $addToSet
;;
(deftest initialize-an-array-using-$addToSet-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet modifier appends value to field unless it is already there"]
(mc/insert db coll {:_id oid :title title})
(mc/update db coll {:_id oid} {$addToSet {:tags "modifiers"}})
(is (= {:_id oid :title title :tags ["modifiers"]}
(mc/find-map-by-id db coll oid)))))
(deftest add-value-to-an-existing-array-using-$addToSet-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet modifier appends value to field unless it is already there"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$addToSet {:tags "modifiers"}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers"]}
(mc/find-map-by-id db coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$addToSet-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet modifier appends value to field unless it is already there"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$addToSet {:tags "modifiers"}})
(mc/update db coll {:_id oid} {$addToSet {:tags "modifiers"}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers"]}
(mc/find-map-by-id db coll oid)))))
;;
;; $addToSet $each
;;
(deftest initialize-an-array-using-$addToSet-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet with $each modifier appends multiple values to field unless they are already there"]
(mc/insert db coll {:_id oid :title title})
(mc/update db coll {:_id oid} {$addToSet {:tags {$each ["mongodb" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "docs"]}
(mc/find-map-by-id db coll oid)))))
(deftest add-values-to-an-existing-array-using-$addToSet-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet with $each modifier appends multiple values to field unless they are already there"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb"]})
(mc/update db coll {:_id oid} {$addToSet {:tags {$each ["modifiers" "docs"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "modifiers" "docs"]}
(mc/find-map-by-id db coll oid)))))
(deftest double-add-value-to-an-existing-array-using-$addToSet-$each-modifier
(let [coll "docs"
oid (ObjectId.)
title "$addToSet with $each modifier appends multiple values to field unless they are already there"]
(mc/insert db coll {:_id oid :title title :tags ["mongodb" "docs"]})
(mc/update db coll {:_id oid} {$addToSet {:tags {$each ["modifiers" "docs" "operators"]}}})
(is (= {:_id oid :title title :tags ["mongodb" "docs" "modifiers" "operators"]}
(mc/find-map-by-id db coll oid)))))
;;
;; $pop
;;
(deftest pop-last-value-in-the-array-using-$pop-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pop modifier removes last or first value in the array"]
(mc/insert db coll {:_id oid :title title :tags ["products" "apple" "reviews"]})
(mc/update db coll {:_id oid} {$pop {:tags 1}})
(is (= {:_id oid :title title :tags ["products" "apple"]}
(mc/find-map-by-id db coll oid)))))
(deftest unshift-first-value-in-the-array-using-$pop-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pop modifier removes last or first value in the array"]
(mc/insert db coll {:_id oid :title title :tags ["products" "apple" "reviews"]})
(mc/update db coll {:_id oid} {$pop {:tags -1}})
(is (= {:_id oid :title title :tags ["apple" "reviews"]}
(mc/find-map-by-id db coll oid)))))
(deftest pop-last-values-from-multiple-arrays-using-$pop-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pop modifier removes last or first value in the array"]
(mc/insert db coll {:_id oid :title title :tags ["products" "apple" "reviews"] :categories ["apple" "reviews" "drafts"]})
(mc/update db coll {:_id oid} {$pop {:tags 1 :categories 1}})
(is (= {:_id oid :title title :tags ["products" "apple"] :categories ["apple" "reviews"]}
(mc/find-map-by-id db coll oid)))))
;;
;; $pull
;;
(deftest remove-all-value-entries-from-array-using-$pull-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pull modifier removes all value entries in the array"]
(mc/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]})
(mc/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]}
(mc/find-map-by-id db coll oid)))))
(deftest remove-all-value-entries-from-array-using-$pull-modifier-based-on-a-condition
(let [coll "docs"
oid (ObjectId.)
title "$pull modifier removes all value entries in the array"]
(mc/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]})
(mc/update db coll {:_id oid} {$pull {:measurements {$gte 1.2}}})
(is (= {:_id oid :title title :measurements [1.0 1.1 1.1 1.0]}
(mc/find-map-by-id db coll oid)))))
;;
;; $pullAll
;;
(deftest remove-all-value-entries-from-array-using-$pullAll-modifier
(let [coll "docs"
oid (ObjectId.)
title "$pullAll modifier removes entries of multiple values in the array"]
(mc/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]})
(mc/update db coll {:_id oid} {$pullAll {:measurements [1.0 1.1 1.2]}})
(is (= {:_id oid :title title :measurements [1.3]}
(mc/find-map-by-id db coll oid)))))
;;
;; $rename
;;
(deftest rename-a-single-field-using-$rename-modifier
(let [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]]
(mc/insert db coll {:_id oid :title title :measurements v})
(mc/update db coll {:_id oid} {$rename {:measurements "results"}})
(is (= {:_id oid :title title :results v}
(mc/find-map-by-id db coll oid)))))
;;
;; find-and-modify
;;
(deftest find-and-modify-a-single-document
(let [coll "docs"
oid (ObjectId.)
doc {:_id oid :name "Sophie Bangs" :level 42}
conditions {:name "Sophie Bangs"}
update {$inc {:level 1}}]
(mc/insert db coll doc)
(let [res (mc/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 [coll "docs"
oid (ObjectId.)
doc {:_id oid :name "Sophie Bangs" :level 42}
conditions {:name "Sophie Bangs"}]
(mc/insert db coll doc)
(let [res (mc/find-and-modify db coll conditions {} {:remove true})]
(is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42}))
(is (empty? (mc/find-maps db coll conditions))))))
(deftest find-and-modify-upsert-a-document
(testing "case 1"
(let [coll "docs"
oid (ObjectId.)
doc {:_id oid :name "Sophie Bangs" :level 42}]
(let [res (mc/find-and-modify db coll doc doc {:upsert true})]
(is (empty? res))
(is (select-keys (mc/find-map-by-id db coll oid) [:name :level]) (dissoc doc :_id)))))
(testing "case 2"
(let [coll "docs"
query {:name "Sophie Bangs"}
doc (merge query {:level 42})]
(let [res (mc/find-and-modify db coll query doc {:upsert true :return-new true})]
(is (:_id res))
(is (select-keys (mc/find-map-by-id db coll (:_id res)) [:name :level]) doc)))))
(deftest find-and-modify-after-sort
(let [coll "docs"
oid (ObjectId.)
oid2 (ObjectId.)
doc {:name "Sophie Bangs"}
doc1 (assoc doc :_id oid :level 42)
doc2 (assoc doc :_id oid2 :level 0)]
(mc/insert-batch db coll [doc1 doc2])
(let [res (mc/find-and-modify db coll doc {$inc {:level 1}} {:sort {:level -1}})]
(is (= (select-keys res [:name :level]) {:name "Sophie Bangs" :level 42}))))))

View file

@ -1,19 +1,42 @@
(ns monger.test.authentication-test
(:require [monger core util db]
[monger.test.helper :as helper])
(:use [clojure.test]))
(:require [monger util db]
[monger.credentials :as mcr]
[monger.core :as mg]
[monger.collection :as mc]
[clojure.test :refer :all]))
(helper/connect!)
;;
;; Connection via URI
;;
(when-not (System/getenv "CI")
(deftest ^{:authentication true} connect-to-mongo-via-uri-without-credentials
(let [{:keys [conn db]} (mg/connect-via-uri "mongodb://127.0.0.1/monger-test4")]
(is (-> conn .getAddress (.sameHost "127.0.0.1")))))
(deftest ^{:authentication true} connect-to-mongo-via-uri-with-valid-credentials
(let [{:keys [conn db]} (mg/connect-via-uri "mongodb://clojurewerkz%2Fmonger:monger@127.0.0.1/monger-test4")]
(is (= "monger-test4" (.getName db)))
(is (-> conn .getAddress (.sameHost "127.0.0.1")))
(mc/remove db "documents")
;; make sure that the database is selected
;; and operations get through.
(mc/insert db "documents" {:field "value"})
(is (= 1 (mc/count db "documents" {}))))))
(if-let [uri (System/getenv "MONGOHQ_URL")]
(deftest ^{:external true :authentication true} connect-to-mongo-via-uri-with-valid-credentials
(let [{:keys [conn db]} (mg/connect-via-uri uri)]
(is (-> conn .getAddress (.sameHost "127.0.0.1"))))))
;;
;; Regular connecton
;;
(deftest test-authentication-with-valid-credentials
;; see ./bin/ci/before_script.sh. MK.
(let [username "clojurewerkz/monger"
pwd "monger"]
(is (monger.core/authenticate "monger-test" username (.toCharArray pwd)))))
(deftest test-authentication-with-invalid-credentials
(let [username "monger"
^String pwd (monger.util/random-str 128 32)]
(is (not (monger.core/authenticate "monger-test2" username (.toCharArray pwd))))))
(deftest ^{:authentication true} test-authentication-with-valid-credentials
;; see ./bin/ci/before_script.sh. MK.
(doseq [s ["monger-test" "monger-test2" "monger-test3" "monger-test4"]]
(let [creds (mcr/create "clojurewerkz/monger" "monger-test" "monger")
conn (mg/connect-with-credentials "127.0.0.1" creds)]
(mc/remove (mg/get-db conn "monger-test") "documents"))))

View file

@ -1,123 +0,0 @@
(ns monger.test.cache-test
(:require [monger.test.helper :as helper]
[monger.collection :as mc])
(:use clojure.core.cache clojure.test monger.cache)
(:import [clojure.core.cache BasicCache FIFOCache LRUCache TTLCache]
java.util.UUID))
;;
;; Playground/Tests. These were necessary because clojure.core.cache has
;; little documentation, incomplete test suite and
;; slightly non-standard (although necessary to support all those cache variations)
;; cache operations protocol.
;;
;; This is by no means clear or complete either but it did the job of helping me
;; explore the API.
(deftest ^{:cache true}
test-has?-with-basic-cache
(testing "that has? returns false for misses"
(let [c (BasicCache. {})]
(are [v] (is (false? (has? c v)))
:missing-key
"missing-key"
(gensym "missing-key"))))
(testing "that has? returns true for hits"
(let [c (BasicCache. {:skey "Value" :lkey (Long/valueOf 10000) "kkey" :keyword})]
(are [v] (is (has? c v))
:skey
:lkey
"kkey"))))
(deftest ^{:cache true}
test-lookup-with-basic-cache
(testing "that lookup returns nil for misses"
(let [c (BasicCache. {})]
(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)
c (BasicCache. {:skey "Value" :lkey l "kkey" :keyword})]
(are [v k] (is (= v (lookup c k)))
"Value" :skey
l :lkey
:keyword "kkey"))))
(deftest ^{:cache true}
test-evict-with-basic-cache
(testing "that evict has no effect for keys that do not exist"
(let [c (atom (BasicCache. {:a 1 :b 2}))]
(swap! c evict :missing-key)
(is (has? @c :a))
(is (has? @c :b))))
(testing "that evict removes keys that did exist"
(let [c (atom (BasicCache. {:skey "Value" "kkey" :keyword}))]
(is (has? @c :skey))
(is (= "Value" (lookup @c :skey)))
(swap! c evict :skey)
(is (not (has? @c :skey)))
(is (= nil (lookup @c :skey)))
(is (has? @c "kkey"))
(is (= :keyword (lookup @c "kkey"))))))
(deftest ^{:cache true}
test-seed-with-basic-cache
(testing "that seed returns a new value"
(let [c (atom (BasicCache. {}))]
(swap! c seed {:a 1 :b "b" "c" :d})
(are [k v] (do
(is (has? @c k))
(is (= v (lookup @c k))))
:a 1
:b "b"
"c" :d))))
;;
;; Tests
;;
(helper/connect!)
(use-fixtures :each (fn [f]
(mc/remove "basic_monger_cache_entries")
(f)
(mc/remove "basic_monger_cache_entries")))
(deftest ^{:cache true}
test-has?-with-basic-monger-cache
(testing "that has? returns false for misses"
(let [coll "basic_monger_cache_entries"
c (basic-monger-cache-factory coll)]
(is (not (has? c (str (UUID/randomUUID)))))
(is (not (has? c (str (UUID/randomUUID)))))))
(testing "that has? returns true for hits"
(let [coll "basic_monger_cache_entries"
c (basic-monger-cache-factory 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 [coll "basic_monger_cache_entries"
c (basic-monger-cache-factory 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)
coll "basic_monger_cache_entries"
c (basic-monger-cache-factory coll {:skey "Value" :lkey l "kkey" :keyword})]
(are [v k] (is (= v (lookup c k)))
"Value" :skey
l :lkey
"keyword" "kkey"))))

View file

@ -1,38 +1,25 @@
(set! *warn-on-reflection* true)
(ns monger.test.capped-collections-test
(:require [monger core util]
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.result :as mres]
[monger.test.helper :as helper])
(:use clojure.test
monger.operators
monger.test.fixtures))
(helper/connect!)
(use-fixtures :each purge-cached)
[clojure.test :refer :all]
[monger.operators :refer :all]))
(defn- megabytes
[^long n]
(* n 1024 1024))
;;
;; Tests
;;
(deftest test-inserting-into-capped-collection
(let [n 1000
cname "cached"
_ (mc/drop cname)
coll (mc/create cname {:capped true :size (-> 16 megabytes) :max n})]
(is (= cname (.getName coll)))
(mc/insert-batch cname (for [i (range 0 (+ n 100))] {:i i}))
(is (= n (mc/count cname)))
;; older elements get replaced by newer ones
(is (not (mc/any? cname {:i 1})))
(is (not (mc/any? cname {:i 5})))
(is (not (mc/any? cname {:i 9})))
(is (mc/any? cname {:i (+ n 80)}))))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(deftest test-inserting-into-capped-collection
(let [n 1000
cname "cached"
_ (mc/drop db cname)
coll (mc/create db cname {:capped true :size (-> 16 megabytes) :max n})]
(is (= cname (.getName coll)))
(mc/insert-batch db cname (for [i (range 0 (+ n 100))] {:i i}))
(is (= n (mc/count db cname)))
;; older elements get replaced by newer ones
(is (not (mc/any? db cname {:i 1})))
(is (not (mc/any? db cname {:i 5})))
(is (not (mc/any? db cname {:i 9})))
(is (mc/any? db cname {:i (+ n 80)})))))

View file

@ -1,153 +1,193 @@
(set! *warn-on-reflection* true)
(ns monger.test.collection-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure MapReduceOutput MapReduceCommand MapReduceCommand$OutputType]
org.bson.types.ObjectId
(:import org.bson.types.ObjectId
java.util.Date)
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.result :as mgres]
[monger.test.helper :as helper])
(:use clojure.test
monger.operators
monger.test.fixtures))
[clojure.test :refer :all]
[monger.operators :refer :all]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(use-fixtures :each purge-people purge-docs purge-things purge-libraries)
(defn purge-collections
[f]
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "libraries")
(f)
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "libraries"))
(use-fixtures :each purge-collections)
;;
;; count, remove
;;
(deftest get-collection-size
(let [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"})))))
;;
;; count, remove
;;
(deftest get-collection-size
(let [collection "things"]
(is (= 0 (mc/count collection)))
(mc/insert-batch collection [{:language "Clojure" :name "langohr"}
{:language "Clojure" :name "monger"}
{:language "Clojure" :name "incanter"}
{:language "Scala" :name "akka"}])
(is (= 4 (mc/count collection)))
(is (mc/any? collection))
(is (= 3 (mc/count mg/*mongodb-database* collection {:language "Clojure"})))
(is (mc/any? mg/*mongodb-database* collection {:language "Clojure"}))
(is (= 1 (mc/count collection {:language "Scala" })))
(is (mc/any? collection {:language "Scala"}))
(is (= 0 (mc/count mg/*mongodb-database* collection {:language "Python" })))
(is (not (mc/any? mg/*mongodb-database* collection {:language "Python"})))))
(deftest remove-all-documents-from-collection
(let [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-all-documents-from-collection
(let [collection "libraries"]
(mc/insert-batch collection [{:language "Clojure" :name "monger"}
{:language "Clojure" :name "langohr"}
{:language "Clojure" :name "incanter"}
{:language "Scala" :name "akka"}])
(is (= 4 (mc/count collection)))
(mc/remove collection)
(is (= 0 (mc/count collection)))))
(deftest remove-some-documents-from-collection
(let [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 [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 remove-some-documents-from-collection
(let [collection "libraries"]
(mc/insert-batch collection [{:language "Clojure" :name "monger"}
{:language "Clojure" :name "langohr"}
{:language "Clojure" :name "incanter"}
{:language "Scala" :name "akka"}])
(is (= 4 (mc/count collection)))
(mc/remove collection {:language "Clojure"})
(is (= 1 (mc/count collection)))))
;;
;; exists?, drop, create
;;
(deftest remove-a-single-document-from-collection
(let [collection "libraries"
oid (ObjectId.)]
(mc/insert-batch collection [{:language "Clojure" :name "monger" :_id oid}])
(mc/remove-by-id collection oid)
(is (= 0 (mc/count collection)))
(is (nil? (mc/find-by-id collection oid)))))
(deftest checking-for-collection-existence-when-it-does-not-exist
(let [collection "widgets"]
(mc/drop db collection)
(is (false? (mc/exists? db collection)))))
(deftest checking-for-collection-existence-when-it-does-exist
(let [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")))
;;
;; any?, empty?
;;
(deftest test-any-on-empty-collection
(let [collection "things"]
(is (not (mc/any? db collection)))))
(deftest test-any-on-non-empty-collection
(let [collection "things"
_ (mc/insert db collection {:language "Clojure" :name "langohr"})]
(is (mc/any? db "things" {:language "Clojure"}))))
(deftest test-empty-on-empty-collection
(let [collection "things"]
(is (mc/empty? db collection))))
(deftest test-empty-on-non-empty-collection
(let [collection "things"
_ (mc/insert db collection {:language "Clojure" :name "langohr"})]
(is (not (mc/empty? db "things")))))
;;
;; exists?, drop, create
;;
;;
;; distinct
;;
(deftest checking-for-collection-existence-when-it-does-not-exist
(let [collection "widgets"]
(mc/drop collection)
(is (false? (mc/exists? collection)))))
(deftest test-distinct-values
(let [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" "IL" "NY"] (sort (mc/distinct db collection :state {}))))
(is (= ["CA" "NY"] (sort (mc/distinct db collection :state {:price {$gt 100.00}}))))))
(deftest checking-for-collection-existence-when-it-does-exist
(let [collection "widgets"]
(mc/drop collection)
(mc/insert-batch collection [{:name "widget1"}
{:name "widget2"}])
(is (mc/exists? collection))
(mc/drop collection)
(is (false? (mc/exists? collection)))
(mc/create "widgets" {:capped true :size 100000 :max 10})
(is (mc/exists? collection))
(mc/rename collection "gadgets")
(is (not (mc/exists? collection)))
(is (mc/exists? "gadgets"))
(mc/drop "gadgets")))
;;
;; update
;;
;;
;; any?, empty?
;;
(let [coll "things"
batch [{:_id 1 :type "rock" :size "small"}
{:_id 2 :type "bed" :size "bed-sized"}
{:_id 3 :type "bottle" :size "1.5 liters"}]]
(deftest test-any-on-empty-collection
(let [collection "things"]
(is (not (mc/any? collection)))))
(deftest test-update
(mc/insert-batch db coll batch)
(is (= "small" (:size (mc/find-one-as-map db coll {:type "rock"}))))
(mc/update db coll {:type "rock"} {"$set" {:size "huge"}})
(is (= "huge" (:size (mc/find-one-as-map db coll {:type "rock"})))))
(deftest test-any-on-non-empty-collection
(let [collection "things"
_ (mc/insert collection {:language "Clojure" :name "langohr"})]
(is (mc/any? "things"))
(is (mc/any? mg/*mongodb-database* "things" {:language "Clojure"}))))
(deftest test-upsert
(is (mc/empty? db coll))
(mc/upsert db coll {:_id 4} {"$set" {:size "tiny"}})
(is (not (mc/empty? db coll)))
(mc/upsert db coll {:_id 4} {"$set" {:size "big"}})
(is (= [{:_id 4 :size "big"}] (mc/find-maps db coll {:_id 4}))))
(deftest test-empty-on-empty-collection
(let [collection "things"]
(is (mc/empty? collection))
(is (mc/empty? mg/*mongodb-database* collection))))
(deftest test-update-by-id
(mc/insert-batch db coll batch)
(is (= "bed" (:type (mc/find-one-as-map db coll {:_id 2}))))
(mc/update-by-id db coll 2 {"$set" {:type "living room"}})
(is (= "living room" (:type (mc/find-one-as-map db coll {:_id 2})))))
(deftest test-empty-on-non-empty-collection
(let [collection "things"
_ (mc/insert collection {:language "Clojure" :name "langohr"})]
(is (not (mc/empty? "things")))))
(deftest test-update-by-ids
(mc/insert-batch db coll batch)
(is (= "bed" (:type (mc/find-one-as-map db coll {:_id 2}))))
(is (= "bottle" (:type (mc/find-one-as-map db coll {:_id 3}))))
(mc/update-by-ids db coll [2 3] {"$set" {:type "dog"}})
(is (= "dog" (:type (mc/find-one-as-map db coll {:_id 2}))))
(is (= "dog" (:type (mc/find-one-as-map db coll {:_id 3}))))))
;;
;; miscellenous
;;
;;
;; distinct
;;
(deftest test-distinct-values
(let [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 collection batch)
(is (= ["CA" "IL" "NY"] (sort (mc/distinct mg/*mongodb-database* collection :state {}))))
(is (= ["CA" "NY"] (sort (mc/distinct collection :state {:price {$gt 100.00}}))))))
;;
;; miscellenous
;;
(deftest test-system-collection-predicate
(are [name] (is (mc/system-collection? name))
"system.indexes"
"system"
;; we treat default GridFS collections as system ones,
;; possibly this is a bad idea, time will tell. MK.
"fs.chunks"
"fs.files")
(are [name] (is (not (mc/system-collection? name)))
"events"
"accounts"
"megacorp_account"
"myapp_development"))
(deftest test-system-collection-predicate
(are [name] (is (mc/system-collection? name))
"system.indexes"
"system"
;; we treat default GridFS collections as system ones,
;; possibly this is a bad idea, time will tell. MK.
"fs.chunks"
"fs.files")
(are [name] (is (not (mc/system-collection? name)))
"events"
"accounts"
"megacorp_account"
"myapp_development")))

View file

@ -1,50 +1,29 @@
(ns monger.test.command-test
(:require [monger.core :as mg]
[monger.command :as mcom]
[monger.test.helper :as helper]
[monger.collection :as mc])
(:use clojure.test
[monger.result :only [ok?]]
[monger.conversion :only [from-db-object]]))
[monger.collection :as mc]
[clojure.test :refer :all]
[monger.result :refer [acknowledged?]]
[monger.conversion :refer [from-db-object]]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(deftest ^{:command true} test-reindex-collection
(let [_ (mc/insert db "test" {:name "Clojure"})
result (mcom/reindex-collection db "test")]
(is (acknowledged? result))))
(deftest ^{:command true} test-server-status
(let [status (mcom/server-status db)]
(is (acknowledged? status))
(is (not-empty status))))
(deftest ^{:command true} test-db-stats
(let [stats (mcom/db-stats)]
(is (ok? stats))
(is (= "monger-test" (get stats "db")))))
(deftest ^{:command true} test-top
(let [result (mcom/top conn)]
(is (acknowledged? result))
(is (not-empty result))))
(deftest ^{:command true} test-collection-stats
(let [collection "stat_test"
_ (mc/insert collection {:name "Clojure"})
check (mc/count collection)
stats (mcom/collection-stats collection)]
(is (ok? stats))
(is (= "monger-test.stat_test" (get stats "ns")))
(is (= check (get stats "count")))))
(deftest ^{:command true} test-reindex-collection
(let [_ (mc/insert "test" {:name "Clojure"})
result (mcom/reindex-collection "test")]
(is (ok? result))
(is (get result "indexes"))))
(deftest ^{:command true} test-server-status
(let [status (mcom/server-status)]
(is (ok? status))
(is (not-empty status))
(is (get status "serverUsed"))))
(deftest ^{:command true} test-top
(let [result (mcom/top)]
(is (ok? result))
(is (not-empty result))
(is (get result "serverUsed"))))
(deftest ^{:command true} test-running-is-master-as-an-arbitrary-command
(let [raw (mg/command {:isMaster 1})
result (from-db-object raw true)]
(is (ok? result))
(is (ok? raw))
(is (:ismaster result))))
(deftest ^{:command true} test-running-is-master-as-an-arbitrary-command
(let [raw (mg/command db {:isMaster 1})
result (from-db-object raw true)]
(is (acknowledged? raw)))))

View file

@ -1,9 +1,11 @@
(ns monger.test.conversion-test
(:require [monger core collection])
(:require [monger core collection]
[clojure.test :refer :all]
[monger.conversion :refer :all])
(:import [com.mongodb DBObject BasicDBObject BasicDBList]
[java.util Date Calendar List ArrayList]
org.bson.types.ObjectId)
(:use clojure.test monger.conversion))
org.bson.types.ObjectId
(org.bson.types Decimal128)))
;;
@ -100,6 +102,13 @@
(is (= 2 (from-db-object 2 false)))
(is (= 2 (from-db-object 2 true))))
(deftest convert-decimal-from-dbobject
(is (= 2.3M (from-db-object (Decimal128. 2.3M) false)))
(is (= 2.3M (from-db-object (Decimal128. 2.3M) true)))
(is (= 2.3M (from-db-object (Decimal128/parse "2.3") true)))
(is (not= 2.32M (from-db-object (Decimal128/parse "2.3") true)))
)
(deftest convert-float-from-dbobject
(is (= 3.3 (from-db-object 3.3 false)))
(is (= 3.3 (from-db-object 3.3 true))))
@ -111,20 +120,20 @@
(.put "name" name)
(.put "age" age))
output (from-db-object input false)]
(is (= (output { "name" name, "age" age })))
(is (= output { "name" name, "age" age }))
(is (= (output "name") name))
(is (nil? (output :name)))
(is (= (output "age") age))
(is (nil? (output "points")))))
(deftest convert-flat-db-object-to-map-without-keywordizing
(deftest convert-flat-db-object-to-map-with-keywordizing
(let [name "Michael"
age 26
input (doto (BasicDBObject.)
(.put "name" name)
(.put "age" age))
output (from-db-object input true)]
(is (= (output { :name name, :age age })))
(is (= output { :name name, :age age }))
(is (= (output :name) name))
(is (nil? (output "name")))
(is (= (output :age) age))

View file

@ -1,79 +1,28 @@
(ns monger.test.core-test
(:require [monger core collection util result]
[monger.test.helper :as helper]
[monger.collection :as mc])
(:import [com.mongodb Mongo DB WriteConcern MongoOptions ServerAddress])
(:use clojure.test
[monger.core :only [server-address mongo-options]]))
(:require [monger util result]
[monger.core :as mg :refer [server-address mongo-options]]
[monger.collection :as mc]
[clojure.test :refer :all])
(:import [com.mongodb MongoClient DB WriteConcern MongoClientOptions ServerAddress]))
(println (str "Using Clojure version " *clojure-version*))
(helper/connect!)
(deftest connect-to-mongo-with-default-host-and-port
(let [connection (monger.core/connect)]
(is (instance? com.mongodb.Mongo connection))))
(let [connection (mg/connect)]
(is (instance? com.mongodb.MongoClient connection))))
(deftest connect-and-disconnect
(let [conn (mg/connect)]
(mg/disconnect conn)))
(deftest connect-to-mongo-with-default-host-and-explicit-port
(let [connection (monger.core/connect { :port 27017 })]
(is (instance? com.mongodb.Mongo connection))))
(let [connection (mg/connect {:port 27017})]
(is (instance? com.mongodb.MongoClient connection))))
(deftest connect-to-mongo-with-default-port-and-explicit-host
(let [connection (monger.core/connect { :host "127.0.0.1" })]
(is (instance? com.mongodb.Mongo connection))))
(when-not (System/getenv "CI")
(deftest connect-to-mongo-via-uri-without-credentials
(let [connection (monger.core/connect-via-uri! "mongodb://127.0.0.1/monger-test4")]
(is (= (-> connection .getAddress ^InetAddress (.sameHost "127.0.0.1")))))
;; reconnect using regular host
(helper/connect!))
(deftest connect-to-mongo-via-uri-with-valid-credentials
(let [connection (monger.core/connect-via-uri! "mongodb://clojurewerkz/monger!:monger!@127.0.0.1/monger-test4")]
(is (= "monger-test4" (.getName (monger.core/current-db))))
(is (= (-> connection .getAddress ^InetAddress (.sameHost "127.0.0.1"))))
(mc/remove "documents")
;; make sure that the database is selected
;; and operations get through.
(mc/insert "documents" {:field "value"})
(is (= 1 (mc/count "documents" {}))))
;; reconnect using regular host
(helper/connect!)))
(if-let [uri (System/getenv "MONGOHQ_URL")]
(deftest ^{:external true} connect-to-mongo-via-uri-with-valid-credentials
(let [connection (monger.core/connect-via-uri! uri)]
(is (= (-> connection .getAddress ^InetAddress (.sameHost "127.0.0.1")))))
;; reconnect using regular host
(helper/connect!)))
(deftest connect-to-mongo-via-uri-with-invalid-credentials
(is (thrown? IllegalArgumentException
(monger.core/connect-via-uri! "mongodb://clojurewerkz/monger!:ahsidaysd78jahsdi8@127.0.0.1/monger-test4"))))
(deftest test-mongo-options-builder
(let [max-wait-time (* 1000 60 2)
^MongoOptions result (monger.core/mongo-options :connections-per-host 3 :threads-allowed-to-block-for-connection-multiplier 50
:max-wait-time max-wait-time :connect-timeout 10 :socket-timeout 10 :socket-keep-alive true
:auto-connect-retry true :max-auto-connect-retry-time 0 :safe true
:w 1 :w-timeout 20 :fsync true :j true)]
(is (= 3 (. result connectionsPerHost)))
(is (= 50 (. result threadsAllowedToBlockForConnectionMultiplier)))
(is (= max-wait-time (.maxWaitTime result)))
(is (= 10 (.connectTimeout result)))
(is (= 10 (.socketTimeout result)))
(is (.socketKeepAlive result))
(is (.autoConnectRetry result))
(is (= 0 (.maxAutoConnectRetryTime result)))
(is (.safe result))
(is (= 1 (.w result)))
(is (= 20 (.wtimeout result)))
(is (.fsync result))
(is (.j result))))
(let [connection (mg/connect {:host "127.0.0.1"})]
(is (instance? com.mongodb.MongoClient connection))))
(deftest test-server-address
(let [host "127.0.0.1"
@ -83,32 +32,58 @@
(is (= port (.getPort sa)))))
(deftest use-existing-mongo-connection
(let [^MongoOptions opts (mongo-options :threads-allowed-to-block-for-connection-multiplier 300)
connection (Mongo. "127.0.0.1" opts)]
(monger.core/set-connection! connection)
(is (= monger.core/*mongodb-connection* connection))))
(let [^MongoClientOptions opts (mongo-options {:threads-allowed-to-block-for-connection-multiplier 300})
connection (MongoClient. "127.0.0.1" opts)
db (mg/get-db connection "monger-test")]
(mg/disconnect connection)))
(deftest connect-to-mongo-with-extra-options
(let [^MongoOptions opts (mongo-options :threads-allowed-to-block-for-connection-multiplier 300)
^ServerAddress sa (server-address "127.0.0.1" 27017)]
(monger.core/connect! sa opts)))
(let [^MongoClientOptions opts (mongo-options {:threads-allowed-to-block-for-connection-multiplier 300})
^ServerAddress sa (server-address "127.0.0.1" 27017)
conn (mg/connect sa opts)]
(mg/disconnect conn)))
(deftest get-database
(let [connection (monger.core/connect)
db (monger.core/get-db connection "monger-test")]
(let [connection (mg/connect)
db (mg/get-db connection "monger-test")]
(is (instance? com.mongodb.DB db))))
(deftest test-get-db-names
(let [dbs (monger.core/get-db-names)]
(let [conn (mg/connect)
dbs (mg/get-db-names conn)]
(is (not (empty? dbs)))
(is (dbs "monger-test"))))
(deftest get-last-error
(let [connection (monger.core/connect)
db (monger.core/get-db connection "monger-test")]
(is (monger.result/ok? (monger.core/get-last-error)))
(is (monger.result/ok? (monger.core/get-last-error db)))
(is (monger.result/ok? (monger.core/get-last-error db WriteConcern/NORMAL)))
(is (monger.result/ok? (monger.core/get-last-error db 1 100 true)))))
(deftest monger-options-test
(let [opts {:always-use-mbeans true
:application-name "app"
:connect-timeout 1
:connections-per-host 1
:cursor-finalizer-enabled true
:description "Description"
:heartbeat-connect-timeout 1
:heartbeat-frequency 1
:heartbeat-socket-timeout 1
:local-threshold 1
:max-connection-idle-time 1
:max-connection-life-time 1
:max-wait-time 1
:min-connections-per-host 1
:min-heartbeat-frequency 1
:required-replica-set-name "rs"
:retry-writes true
:server-selection-timeout 1
:socket-keep-alive true
:socket-timeout 1
:ssl-enabled true
:ssl-invalid-host-name-allowed true
:threads-allowed-to-block-for-connection-multiplier 1
:uuid-representation org.bson.UuidRepresentation/STANDARD
:write-concern com.mongodb.WriteConcern/JOURNAL_SAFE}]
(is (instance? com.mongodb.MongoClientOptions$Builder (mg/mongo-options-builder opts)))))
(deftest connect-to-uri-without-db-name
(let [uri "mongodb://localhost:27017"]
(is (thrown? IllegalArgumentException (mg/connect-via-uri uri)))))

View file

@ -0,0 +1,107 @@
(ns monger.test.cursor-test
(:import [com.mongodb DBCursor DBObject Bytes]
[java.util List Map])
(:require [monger.core :as mg]
[clojure.test :refer :all]
[monger.cursor :refer :all]))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(deftest make-db-cursor-for-collection
(is (= DBCursor
(class (make-db-cursor db :docs)))))
(deftest getting-cursor-options-value
(let [db-cur (make-db-cursor db :docs)
opts (get-options db-cur)]
(is (= true (isa? (class opts) Map)))
(is (= 0 (.getOptions db-cur))) ;;test default value
(is (= false (:notimeout opts)))
(is (= false (:partial opts)))
(is (= false (:awaitdata opts)))
(is (= false (:oplogreplay opts)))
(is (= false (:slaveok opts)))
(is (= false (:tailable opts)))))
(deftest adding-option-to-cursor
(let [db-cur (make-db-cursor db :docs)]
(add-option! db-cur :notimeout)
(is (= (:notimeout cursor-options)
(.getOptions db-cur)))
(add-option! db-cur :tailable)
(is (= (.getOptions db-cur)
(bit-or (:notimeout cursor-options)
(:tailable cursor-options))))))
(deftest remove-option-from-cursor
(let [db-cur (make-db-cursor db :docs)]
(add-option! db-cur :partial)
(add-option! db-cur :awaitdata)
;; removing not-set option should not affect result
(remove-option! db-cur :notimeout)
(is (= (.getOptions db-cur)
(bit-or (:partial cursor-options)
(:awaitdata cursor-options))))
;; removing active option should remove correct value
(remove-option! db-cur :awaitdata)
(is (= (.getOptions db-cur)
(:partial cursor-options)))))
(deftest test-reset-options
(let [db-cur (make-db-cursor db :docs)]
(add-option! db-cur :partial)
(is (= (.getOptions db-cur)
(:partial cursor-options)))
(is (= 0
(int (.getOptions (reset-options db-cur)))))))
(deftest add-options-with-hashmap
(let [db-cur (make-db-cursor db :docs)
_ (add-options db-cur {:notimeout true :slaveok true})
opts (get-options db-cur)]
(is (= true (:notimeout opts)))
(is (= true (:slaveok opts)))
(is (= false (:tailable opts)))
(is (= false (:oplogreplay opts)))))
(deftest add-options-with-hashmap-and-remove-option
(let [db-cur (make-db-cursor db :docs)
_ (add-options db-cur {:notimeout true :slaveok true})
opts (get-options db-cur)]
(is (= true (:notimeout opts)))
(is (= true (:slaveok opts)))
;;remove key and add another option
(add-options db-cur {:partial true :slaveok false})
(let [opts (get-options db-cur)]
(is (= true (:notimeout opts)))
(is (= true (:partial opts)))
(is (= false (:slaveok opts)))
(is (= false (:tailable opts))))))
(deftest add-options-with-list
(let [db-cur (make-db-cursor db :docs)
_ (add-options db-cur [:notimeout :slaveok])
opts (get-options db-cur)]
(is (= true (:notimeout opts)))
(is (= true (:slaveok opts)))
(is (= false (:tailable opts)))
(is (= false (:oplogreplay opts)))))
(deftest add-options-with-Bytes
(let [db-cur (make-db-cursor db :docs)
_ (add-options db-cur Bytes/QUERYOPTION_NOTIMEOUT)
opts (get-options db-cur)]
(is (= true (:notimeout opts)))
(is (= false (:slaveok opts)))
(is (= false (:tailable opts)))
(is (= false (:oplogreplay opts)))))
(deftest add-options-with-one-keyword
(let [db-cur (make-db-cursor db :docs)
_ (add-options db-cur :notimeout)
opts (get-options db-cur)]
(is (= true (:notimeout opts)))
(is (= false (:slaveok opts)))
(is (= false (:tailable opts)))
(is (= false (:oplogreplay opts))))))

View file

@ -1,54 +1,31 @@
(ns monger.test.db-test
(:require [monger core db]
[monger.test.helper :as helper]
[monger.collection :as mc])
(:require [monger.db :as mdb]
[monger.core :as mg]
[monger.collection :as mc]
[clojure.test :refer :all])
(:import [com.mongodb Mongo DB]
java.util.Set)
(:use clojure.test))
(helper/connect!)
(deftest test-add-user
(let [username "clojurewerkz/monger!"
pwd (.toCharArray "monger!")
db-name "monger-test4"]
;; use a secondary database here. MK.
(monger.core/with-db (monger.core/get-db db-name)
(monger.db/add-user username pwd)
(is (monger.core/authenticate db-name username pwd)))))
java.util.Set))
;; do not run this test for CI, it complicates matters by messing up
;; authentication for some other tests :( MK.
(when-not (System/getenv "CI")
(deftest test-drop-database
;; drop a secondary database here. MK.
(monger.core/with-db (monger.core/get-db "monger-test3")
(let [collection "test"
_ (mc/insert collection {:name "Clojure"})
check (mc/count collection)
_ (monger.db/drop-db)]
(let [conn (mg/connect)]
(when-not (System/getenv "CI")
(deftest test-drop-database
;; drop a secondary database here. MK.
(let [db (mg/get-db conn "monger-test3")
collection "test"
_ (mc/insert db collection {:name "Clojure"})
check (mc/count db collection)
_ (mdb/drop-db db)]
(is (= 1 check))
(is (not (mc/exists? collection)))
(is (= 0 (mc/count collection))))))
(is (not (mc/exists? db collection)))
(is (= 0 (mc/count db collection))))))
(deftest test-use-database
(monger.core/use-db! "monger-test5")
(is (= "monger-test5" (.getName (monger.core/current-db))))
(let [collection "test"
_ (mc/insert collection {:name "Clojure"})
check (mc/count collection)
_ (monger.db/drop-db)]
(is (= 1 check))
(is (not (mc/exists? collection)))
(is (= 0 (mc/count collection))))))
(deftest test-get-collection-names
(mc/insert "test-1" {:name "Clojure"})
(mc/insert "test-2" {:name "Clojure"})
(let [^Set collections (monger.db/get-collection-names)]
(is (.contains collections "test-1"))
(is (.contains collections "test-2"))))
(deftest test-get-collection-names
(let [db (mg/get-db conn "monger-test")]
(mc/insert db "test-1" {:name "Clojure"})
(mc/insert db "test-2" {:name "Clojure"})
(let [^Set xs (mdb/get-collection-names db)]
(is (.contains xs "test-1"))
(is (.contains xs "test-2"))))))

View file

@ -1,155 +0,0 @@
(ns monger.test.factory-dsl-test
(:use clojure.test
[monger testkit joda-time]
monger.test.fixtures
[clj-time.core :only [days ago weeks now]])
(:require [monger.collection :as mc]
[monger.test.helper :as helper])
(:import org.bson.types.ObjectId
org.joda.time.DateTime))
(helper/connect!)
(use-fixtures :each purge-domains purge-pages)
(defaults-for "domains"
:ipv6-enabled false)
(let [coll "domains"]
(factory coll "clojure"
:name "clojure.org"
:created-at (-> 2 days ago)
:embedded [(embedded-doc "pages" "http://clojure.org/lisp")
(embedded-doc "pages" "http://clojure.org/jvm_hosted")
(embedded-doc "pages" "http://clojure.org/runtime_polymorphism")])
(factory coll "elixir"
:_id (memoized-oid coll "elixir")
:name "elixir-lang.org"
:created-at (fn [] (now))
:topics (fn [] ["programming" "erlang" "beam" "ruby"])
:related {
:terms (fn [] ["erlang" "python" "ruby"])
}))
(let [coll "pages"]
(factory coll "http://clojure.org/rationale"
:name "/rationale"
:domain-id (parent-id "domains" "clojure"))
(factory coll "http://clojure.org/jvm_hosted"
:name "/jvm_hosted")
(factory coll "http://clojure.org/runtime_polymorphism"
:name "/runtime_polymorphism")
(factory coll "http://clojure.org/lisp"
:name "/lisp")
(factory coll "http://elixir-lang.org/getting_started"
:name "/getting_started/1.html"
:domain-id (memoized-oid "domains" "elixir")))
(deftest test-building-documents-from-a-factory-case-1
(let [t (-> 2 weeks ago)
doc (build "domains" "clojure" :created-at t)]
(is (:_id doc))
(is (= t (:created-at doc)))
(is (= "clojure.org" (:name doc)))
(is (false? (:ipv6-enabled doc)))))
(deftest test-building-documents-from-a-factory-case-2
(let [oid (ObjectId.)
doc (build "domains" "clojure" :_id oid)]
(is (= oid (:_id doc)))
(is (= "clojure.org" (:name doc)))
(is (false? (:ipv6-enabled doc)))))
(deftest test-building-documents-from-a-factory-case-3
(let [oid (ObjectId.)
t (-> 3 weeks ago)
doc (build "domains" "clojure" :_id oid :created-at t :name "clojurewerkz.org" :ipv6-enabled true)]
(is (= oid (:_id doc)))
(is (= t (:created-at doc)))
(is (= "clojurewerkz.org" (:name doc)))
(is (:ipv6-enabled doc))
(is (= ["/lisp" "/jvm_hosted" "/runtime_polymorphism"]
(vec (map :name (:embedded doc)))))))
(deftest test-building-documents-from-a-factory-case-4
(let [doc (build "domains" "elixir")]
(is (:_id doc))
(is (= (:_id doc) (memoized-oid "domains" "elixir")))
(is (instance? DateTime (:created-at doc)))
(is (= ["erlang" "python" "ruby"] (get-in doc [:related :terms])))
(is (= "elixir-lang.org" (:name doc)))
(is (not (:ipv6-enabled doc)))))
(deftest test-building-child-documents-with-a-parent-ref-case-1
(let [doc (build "pages" "http://clojure.org/rationale")]
(is (:domain-id doc))))
(deftest test-building-child-documents-that-use-memoized-oids-for-parents
(let [doc (build "pages" "http://elixir-lang.org/getting_started")]
(is (= (:domain-id doc) (memoized-oid "domains" "elixir")))))
(deftest test-seeding-documents-using-a-factory-case-1
(is (mc/empty? "domains"))
(let [t (-> 2 weeks ago)
doc (seed "domains" "clojure" :created-at t)]
(is (= 1 (mc/count "domains")))
(is (:_id doc))
(is (= (:_id doc) (last-oid-of "domains" "clojure")))
(is (= t (:created-at doc)))
(is (= "clojure.org" (:name doc)))
(is (false? (:ipv6-enabled doc)))))
(deftest test-seeding-documents-using-a-factory-case-2
(is (mc/empty? "domains"))
(let [doc (seed "domains" "elixir")
loaded (first (mc/find-maps "domains"))]
(is (= 1 (mc/count "domains")))
(is (:_id doc))
(is (= (:_id doc) (:_id loaded)))
(is (instance? DateTime (:created-at loaded)))
(is (= ["erlang" "python" "ruby"] (get-in loaded [:related :terms])))
(is (= "elixir-lang.org" (:name loaded)))
(is (not (:ipv6-enabled loaded)))))
(deftest test-seeding-child-documents-with-a-parent-ref-case-1
(is (mc/empty? "domains"))
(is (mc/empty? "pages"))
(let [page (seed "pages" "http://clojure.org/rationale")
domain (mc/find-map-by-id "domains" (:domain-id page))]
(is (= 1 (mc/count "domains")))
(is (= 1 (mc/count "pages")))
(is domain)
(is (:domain-id page))
(is (= "clojure.org" (:name domain)))
(is (= "/rationale" (:name page)))))
(deftest test-seeding-all-factories-in-a-group
(is (mc/empty? "domains"))
(is (mc/empty? "pages"))
(seed-all "pages")
(is (>= (mc/count "domains") 1))
(is (>= (mc/count "pages") 4)))
(deftest test-named-memoized-object-ids
(let [oid1 (memoized-oid "domains" "clojure.org")
oid2 (memoized-oid "domains" "python.org")]
(is (= oid1 (memoized-oid "domains" "clojure.org")))
(is (= oid1 (memoized-oid "domains" "clojure.org")))
(is (= oid1 (memoized-oid "domains" "clojure.org")))
(is (= oid1 (memoized-oid "domains" "clojure.org")))
(is (not (= oid1 oid2)))
(is (= oid2 (memoized-oid "domains" "python.org")))
(is (= oid2 (memoized-oid "domains" "python.org")))
(is (= oid2 (memoized-oid "domains" "python.org")))))

View file

@ -1,20 +0,0 @@
(ns monger.test.fixtures
(:require [monger.collection :as mgcol])
(:use monger.testkit))
;;
;; fixture functions
;;
(defcleaner people "people")
(defcleaner docs "docs")
(defcleaner things "things")
(defcleaner libraries "libraries")
(defcleaner scores "scores")
(defcleaner locations "locations")
(defcleaner domains "domains")
(defcleaner pages "pages")
(defcleaner cached "cached")
(defcleaner migrations "meta.migrations")

View file

@ -0,0 +1,28 @@
(ns monger.test.full-text-search-test
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.command :as cmd]
[monger.operators :refer :all]
[clojure.test :refer [deftest is use-fixtures]]
[monger.result :refer [acknowledged?]])
(:import com.mongodb.BasicDBObjectBuilder))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
coll "search-docs"]
(defn purge-collections
[f]
(mc/purge-many db [coll])
(f)
(mc/purge-many db [coll]))
(use-fixtures :each purge-collections)
(deftest ^{:search true} test-basic-full-text-search-query
(mc/ensure-index db coll (array-map :subject "text" :content "text"))
(mc/insert db coll {:subject "hello there" :content "this should be searchable"})
(mc/insert db coll {:subject "untitled" :content "this is just noize"})
(let [xs (mc/find-maps db coll {$text {$search "hello"}})]
(is (= 1 (count xs)))
(is (= "hello there" (-> xs first :subject))))))

View file

@ -1,166 +1,212 @@
(ns monger.test.gridfs-test
(:refer-clojure :exclude [count remove find])
(:use clojure.test
[monger.core :only [count]]
monger.test.fixtures
[monger operators conversion]
[monger.gridfs :only (store make-input-file store-file filename content-type metadata)])
(:require [monger.gridfs :as gridfs]
[monger.test.helper :as helper]
[clojure.java.io :as io])
[clojure.java.io :as io]
[clojure.test :refer :all]
[monger.core :as mg :refer [count]]
[monger.operators :refer :all]
[monger.conversion :refer :all]
[monger.gridfs :refer [store make-input-file store-file filename content-type metadata]])
(:import [java.io InputStream File FileInputStream]
[com.mongodb.gridfs GridFS GridFSInputFile GridFSDBFile]))
(defn purge-gridfs*
[]
(gridfs/remove-all))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
fs (mg/get-gridfs conn "monger-test")]
(defn purge-gridfs*
[]
(gridfs/remove-all fs))
(defn purge-gridfs
[f]
(gridfs/remove-all)
(f)
(gridfs/remove-all))
(defn purge-gridfs
[f]
(gridfs/remove-all fs)
(f)
(gridfs/remove-all fs))
(use-fixtures :each purge-gridfs)
(use-fixtures :each purge-gridfs)
(helper/connect!)
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-relative-fs-paths
(let [input "./test/resources/mongo/js/mapfun1.js"]
(is (= 0 (count (gridfs/all-files fs))))
(store (make-input-file fs input)
(.setFilename "monger.test.gridfs.file1")
(.setContentType "application/octet-stream"))
(is (= 1 (count (gridfs/all-files fs))))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-file-instances
(let [input (io/as-file "./test/resources/mongo/js/mapfun1.js")]
(is (= 0 (count (gridfs/all-files fs))))
(store-file (make-input-file fs input)
(filename "monger.test.gridfs.file2")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files fs))))))
(deftest ^{:gridfs true} test-storing-bytes-to-gridfs
(let [input (.getBytes "A string")
md {:format "raw" :source "AwesomeCamera D95"}
fname "monger.test.gridfs.file3"
ct "application/octet-stream"]
(is (= 0 (count (gridfs/all-files fs))))
(store-file (make-input-file fs input)
(filename fname)
(metadata md)
(content-type "application/octet-stream"))
(let [f (first (gridfs/files-as-maps fs))]
(is (= ct (:contentType f)))
(is (= fname (:filename f)))
(is (= md (:metadata f))))
(is (= 1 (count (gridfs/all-files fs))))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-absolute-fs-paths
(let [tmp-file (File/createTempFile "monger.test.gridfs" "test-storing-files-to-gridfs-using-absolute-fs-paths")
_ (spit tmp-file "Some content")
input (.getAbsolutePath tmp-file)]
(is (= 0 (count (gridfs/all-files fs))))
(store-file (make-input-file fs input)
(filename "monger.test.gridfs.file4")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files fs))))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-input-stream
(let [tmp-file (File/createTempFile "monger.test.gridfs" "test-storing-files-to-gridfs-using-input-stream")
_ (spit tmp-file "Some other content")]
(is (= 0 (count (gridfs/all-files fs))))
(store-file fs
(make-input-file (FileInputStream. tmp-file))
(filename "monger.test.gridfs.file4b")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files fs))))))
(deftest ^{:gridfs true} test-deleting-file-instance-on-disk-after-storing
(let [tmp-file (File/createTempFile "monger.test.gridfs" "test-deleting-file-instance-on-disk-after-storing")
_ (spit tmp-file "to be deleted")]
(is (= 0 (count (gridfs/all-files fs))))
(store-file (make-input-file fs tmp-file)
(filename "test-deleting-file-instance-on-disk-after-storing")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files fs))))
(is (.delete tmp-file))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-relative-fs-paths
(let [input "./test/resources/mongo/js/mapfun1.js"]
(is (= 0 (count (gridfs/all-files))))
(store (make-input-file input)
(.setFilename "monger.test.gridfs.file1")
(.setContentType "application/octet-stream"))
(is (= 1 (count (gridfs/all-files))))))
(deftest ^{:gridfs true} test-finding-individual-files-on-gridfs
(testing "gridfs/find-one"
(purge-gridfs*)
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
fname "monger.test.gridfs.file5"
md5 "14a09deabb50925a3381315149017bbd"
stored (store-file (make-input-file fs input)
(filename fname)
(content-type ct))]
(is (= 1 (count (gridfs/all-files fs))))
(is (:_id stored))
(is (:uploadDate stored))
(is (= 62 (:length stored)))
(is (= md5 (:md5 stored)))
(is (= fname (:filename stored)))
(is (= ct (:contentType stored)))
(are [a b] (is (= a (:md5 (from-db-object (gridfs/find-one fs b) true))))
md5 {:_id (:_id stored)}
md5 (to-db-object {:md5 md5}))))
(testing "gridfs/find-one-as-map"
(purge-gridfs*)
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
fname "monger.test.gridfs.file6"
md5 "14a09deabb50925a3381315149017bbd"
stored (store-file (make-input-file fs input)
(filename fname)
(metadata (to-db-object {:meta "data"}))
(content-type ct))]
(is (= 1 (count (gridfs/all-files fs))))
(is (:_id stored))
(is (:uploadDate stored))
(is (= 62 (:length stored)))
(is (= md5 (:md5 stored)))
(is (= fname (:filename stored)))
(is (= ct (:contentType stored)))
(let [m (gridfs/find-one-as-map fs {:filename fname})]
(is (= {:meta "data"} (:metadata m))))
(are [a query] (is (= a (:md5 (gridfs/find-one-as-map fs query))))
md5 {:_id (:_id stored)}
md5 {:md5 md5})))
(testing "gridfs/find-by-id"
(purge-gridfs*)
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
fname "monger.test.gridfs.file5"
md5 "14a09deabb50925a3381315149017bbd"
stored (store-file (make-input-file fs input)
(filename fname)
(content-type ct))]
(is (= 1 (count (gridfs/all-files fs))))
(is (:_id stored))
(is (:uploadDate stored))
(is (= 62 (:length stored)))
(is (= md5 (:md5 stored)))
(is (= fname (:filename stored)))
(is (= ct (:contentType stored)))
(are [a id] (is (= a (:md5 (from-db-object (gridfs/find-by-id fs id) true))))
md5 (:_id stored))))
(testing "gridfs/find-map-by-id"
(purge-gridfs*)
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
fname "monger.test.gridfs.file6"
md5 "14a09deabb50925a3381315149017bbd"
stored (store-file (make-input-file fs input)
(filename fname)
(metadata (to-db-object {:meta "data"}))
(content-type ct))]
(is (= 1 (count (gridfs/all-files fs))))
(is (:_id stored))
(is (:uploadDate stored))
(is (= 62 (:length stored)))
(is (= md5 (:md5 stored)))
(is (= fname (:filename stored)))
(is (= ct (:contentType stored)))
(let [m (gridfs/find-map-by-id fs (:_id stored))]
(is (= {:meta "data"} (:metadata m))))
(are [a id] (is (= a (:md5 (gridfs/find-map-by-id fs id))))
md5 (:_id stored)))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-file-instances
(let [input (io/as-file "./test/resources/mongo/js/mapfun1.js")]
(is (= 0 (count (gridfs/all-files))))
(store-file (make-input-file input)
(filename "monger.test.gridfs.file2")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files))))))
(deftest ^{:gridfs true} test-storing-bytes-to-gridfs
(let [input (.getBytes "A string")
md {:format "raw" :source "AwesomeCamera D95"}
fname "monger.test.gridfs.file3"
ct "application/octet-stream"]
(is (= 0 (count (gridfs/all-files))))
(store-file (make-input-file input)
(filename fname)
(metadata md)
(content-type "application/octet-stream"))
(let [f (first (gridfs/files-as-maps))]
(is (= ct (:contentType f)))
(is (= fname (:filename f)))
(is (= md (:metadata f))))
(is (= 1 (count (gridfs/all-files))))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-absolute-fs-paths
(let [tmp-file (File/createTempFile "monger.test.gridfs" "test-storing-files-to-gridfs-using-absolute-fs-paths")
_ (spit tmp-file "Some content")
input (.getAbsolutePath tmp-file)]
(is (= 0 (count (gridfs/all-files))))
(store-file (make-input-file input)
(filename "monger.test.gridfs.file4")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files))))))
(deftest ^{:gridfs true} test-storing-files-to-gridfs-using-input-stream
(let [tmp-file (File/createTempFile "monger.test.gridfs" "test-storing-files-to-gridfs-using-input-stream")
_ (spit tmp-file "Some other content")]
(is (= 0 (count (gridfs/all-files))))
(store-file (make-input-file (FileInputStream. tmp-file))
(filename "monger.test.gridfs.file4b")
(content-type "application/octet-stream"))
(is (= 1 (count (gridfs/all-files))))))
(deftest ^{:gridfs true} test-finding-individual-files-on-gridfs
(testing "gridfs/find-one"
(purge-gridfs*)
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
fname "monger.test.gridfs.file5"
md5 "14a09deabb50925a3381315149017bbd"
stored (store-file (make-input-file input)
(filename fname)
(content-type ct))]
(is (= 1 (count (gridfs/all-files))))
(is (:_id stored))
(is (:uploadDate stored))
(is (= 62 (:length stored)))
(is (= md5 (:md5 stored)))
(is (= fname (:filename stored)))
(is (= ct (:contentType stored)))
(are [a b] (is (= a (:md5 (from-db-object (gridfs/find-one b) true))))
md5 (:_id stored)
md5 fname
md5 (to-db-object {:md5 md5}))))
(testing "gridfs/find-one-as-map"
(purge-gridfs*)
(deftest ^{:gridfs true} test-finding-multiple-files-on-gridfs
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
fname "monger.test.gridfs.file6"
md5 "14a09deabb50925a3381315149017bbd"
stored (store-file (make-input-file input)
(filename fname)
(metadata (to-db-object {:meta "data"}))
(content-type ct))]
(is (= 1 (count (gridfs/all-files))))
(is (:_id stored))
(is (:uploadDate stored))
(is (= 62 (:length stored)))
(is (= md5 (:md5 stored)))
(is (= fname (:filename stored)))
(is (= ct (:contentType stored)))
(let [m (gridfs/find-one-as-map {:filename fname})]
(is (= {:meta "data"} (:metadata m))))
(are [a query] (is (= a (:md5 (gridfs/find-one-as-map query))))
md5 (:_id stored)
md5 fname
md5 {:md5 md5}))))
(deftest ^{:gridfs true} test-finding-multiple-files-on-gridfs
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
md5 "14a09deabb50925a3381315149017bbd"
stored1 (store-file (make-input-file input)
(filename "monger.test.gridfs.file6")
(content-type ct))
stored2 (store-file (make-input-file input)
(filename "monger.test.gridfs.file7")
(content-type ct))
list1 (gridfs/find "monger.test.gridfs.file6")
list2 (gridfs/find "monger.test.gridfs.file7")
list3 (gridfs/find "888000___.monger.test.gridfs.file")
list4 (gridfs/find { :md5 md5 })]
(is (= 2 (count (gridfs/all-files))))
(are [a b] (is (= (map #(.get ^GridFSDBFile % "_id") a)
(map :_id b)))
list1 [stored1]
list2 [stored2]
list3 []
list4 [stored1 stored2])))
stored1 (store-file (make-input-file fs input)
(filename "monger.test.gridfs.file6")
(content-type ct))
stored2 (store-file (make-input-file fs input)
(filename "monger.test.gridfs.file7")
(content-type ct))
list1 (gridfs/find-by-filename fs "monger.test.gridfs.file6")
list2 (gridfs/find-by-filename fs "monger.test.gridfs.file7")
list3 (gridfs/find-by-filename fs "888000___.monger.test.gridfs.file")
list4 (gridfs/find-by-md5 fs md5)]
(is (= 2 (count (gridfs/all-files fs))))
(are [a b] (is (= (map #(.get ^GridFSDBFile % "_id") a)
(map :_id b)))
list1 [stored1]
list2 [stored2]
list3 []
list4 [stored1 stored2])))
(deftest ^{:gridfs true} test-removing-multiple-files-from-gridfs
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
md5 "14a09deabb50925a3381315149017bbd"
stored1 (store-file (make-input-file input)
(filename "monger.test.gridfs.file8")
(content-type ct))
stored2 (store-file (make-input-file input)
(filename "monger.test.gridfs.file9")
(content-type ct))]
(is (= 2 (count (gridfs/all-files))))
(gridfs/remove { :filename "monger.test.gridfs.file8" })
(is (= 1 (count (gridfs/all-files))))
(gridfs/remove { :md5 md5 })
(is (= 0 (count (gridfs/all-files))))))
(deftest ^{:gridfs true} test-removing-multiple-files-from-gridfs
(let [input "./test/resources/mongo/js/mapfun1.js"
ct "binary/octet-stream"
md5 "14a09deabb50925a3381315149017bbd"
stored1 (store-file (make-input-file fs input)
(filename "monger.test.gridfs.file8")
(content-type ct))
stored2 (store-file (make-input-file fs input)
(filename "monger.test.gridfs.file9")
(content-type ct))]
(is (= 2 (count (gridfs/all-files fs))))
(gridfs/remove fs { :filename "monger.test.gridfs.file8" })
(is (= 1 (count (gridfs/all-files fs))))
(gridfs/remove fs { :md5 md5 })
(is (= 0 (count (gridfs/all-files fs)))))))

View file

@ -1,17 +0,0 @@
(ns monger.test.helper
(:require [monger core util])
(:import [com.mongodb WriteConcern]))
(def connected (atom false))
(defn connected?
[]
@connected)
(defn connect!
[]
(when-not (connected?)
(do
(monger.core/connect!)
(monger.core/set-db! (monger.core/get-db "monger-test"))
(monger.core/set-default-write-concern! WriteConcern/SAFE)
(reset! connected true))))

View file

@ -1,53 +1,49 @@
(ns monger.test.indexing-test
(:import org.bson.types.ObjectId
java.util.Date)
(:require [monger core util]
(:require [monger.core :as mg]
[monger.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]]))
monger.joda-time
[clojure.test :refer :all]
[clj-time.core :refer [now seconds ago from-now]]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(deftest ^{:indexing true} test-creating-and-dropping-indexes
(let [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-indexes db collection)
(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/drop-indexes db collection)
(mc/ensure-index db collection (array-map "language" 1))
(mc/drop-indexes db collection)
(mc/ensure-index db collection (array-map "language" 1) {:unique true})
(mc/drop-indexes db collection)
(mc/ensure-index db collection (array-map "language" 1) "index-name" true)
(mc/drop-indexes db collection)))
;;
;; indexes
;;
(deftest ^{:indexing true} test-creating-and-dropping-indexes
(let [collection "libraries"]
(mc/drop-indexes collection)
(mc/create-index collection { "language" 1 })
(is (= "language_1"
(:name (second (mc/indexes-on collection)))))
(mc/drop-index collection "language_1")
(mc/create-index collection ["language"])
(mc/drop-index collection "language_1")
(is (nil? (second (mc/indexes-on collection))))
(mc/ensure-index collection { "language" 1 } {:unique true})
(is (= "language_1"
(:name (second (mc/indexes-on collection)))))
(mc/ensure-index collection { "language" 1 })
(mc/ensure-index collection { "language" 1 } { :unique true })
(mc/drop-indexes collection)))
(deftest ^{:indexing true :edge-features true :time-consuming true} test-ttl-collections
(let [coll "recent_events"
ttl 30
sleep 120]
(mc/remove coll)
(mc/ensure-index coll {:created-at 1} {:expireAfterSeconds ttl})
(dotimes [i 100]
(mc/insert coll {:type "signup" :created-at (-> i secs ago) :i i}))
(dotimes [i 100]
(mc/insert coll {:type "signup" :created-at (-> i secs from-now) :i i}))
(is (= 200 (mc/count 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 coll {:type "signup"})))
(is (< (mc/count coll {:type "signup"}) 100))
(mc/remove coll)))
(deftest ^{:indexing true :time-consuming true} test-ttl-collections
(let [coll "recent_events"
ttl 15
sleep 65]
(mc/remove db coll)
(mc/drop-indexes 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 seconds ago) :i i}))
(dotimes [i 100]
(mc/insert db coll {:type "signup" :created-at (-> i seconds from-now) :i i}))
(is (= 200 (mc/count db coll {:type "signup"})))
;; sleep for > 60 seconds. MongoDB seems to run TTLMonitor once per minute, according to
;; the log.
(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))))

View file

@ -1,5 +1,3 @@
(set! *warn-on-reflection* true)
(ns monger.test.inserting-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject DBRef]
org.bson.types.ObjectId
@ -7,155 +5,176 @@
(:require [monger.core :as mg]
[monger.util :as mu]
[monger.collection :as mc]
[monger.test.helper :as helper])
(:use clojure.test
monger.operators
monger.conversion
monger.test.fixtures))
(helper/connect!)
(use-fixtures :each purge-people purge-docs purge-things purge-libraries)
;;
;; insert
;;
(deftest insert-a-basic-document-without-id-and-with-default-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}]
(is (monger.result/ok? (mc/insert "people" doc)))
(is (= 1 (mc/count collection)))))
(deftest insert-a-basic-document-with-explicitly-passed-database-without-id-and-with-default-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}]
(dotimes [n 5]
(is (monger.result/ok? (mc/insert monger.core/*mongodb-database* "people" doc WriteConcern/SAFE))))
(is (= 5 (mc/count collection)))))
(deftest insert-a-basic-document-without-id-and-with-explicit-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}]
(is (monger.result/ok? (mc/insert "people" doc WriteConcern/SAFE)))
(is (= 1 (mc/count collection)))))
(deftest insert-a-basic-db-object-without-id-and-with-default-write-concern
(let [collection "people"
doc (to-db-object {:name "Joe" :age 30})]
(is (nil? (.get ^DBObject doc "_id")))
(mc/insert "people" doc)
(is (not (nil? (monger.util/get-id doc))))))
(deftest insert-a-map-with-id-and-with-default-write-concern
(let [collection "people"
id (ObjectId.)
doc {:name "Joe" :age 30 "_id" id}
result (mc/insert "people" doc)]
(is (= id (monger.util/get-id doc)))))
(deftest insert-a-document-with-clojure-ratio-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:ratio 11/2 "_id" id}
result (mc/insert "widgets" doc)]
(is (= 5.5 (:ratio (mc/find-map-by-id collection id))))))
(deftest insert-a-document-with-clojure-keyword-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:keyword :kwd "_id" id}
result (mc/insert "widgets" doc)]
(is (= (name :kwd) (:keyword (mc/find-map-by-id collection id))))))
(deftest insert-a-document-with-clojure-keyword-in-a-set-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:keyword1 {:keyword2 #{:kw1 :kw2}} "_id" id}
result (mc/insert "widgets" doc)]
(is (= (sort ["kw1" "kw2"])
(sort (get-in (mc/find-map-by-id collection id) [:keyword1 :keyword2]))))))
[clojure.test :refer :all]
[monger.operators :refer :all]
[monger.conversion :refer :all]))
(defrecord Metrics
[rps eps])
(deftest insert-a-document-with-clojure-record-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:record (Metrics. 10 20) "_id" id}
result (mc/insert "widgets" doc)]
(is (= {:rps 10 :eps 20} (:record (mc/find-map-by-id collection id))))))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-collections
[f]
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "widgets")
(f)
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "widgets"))
(deftest test-insert-a-document-with-dbref
(let [coll1 "widgets"
coll2 "owners"
oid (ObjectId.)
joe (mc/insert "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 coll1 {:type "pentagon"})
fo (:owner fetched)]
(is (= {:_id oid :name "Joe"} (from-db-object @fo true))))))
(use-fixtures :each purge-collections)
;;
;; insert-and-return
;;
;;
;; insert
;;
(deftest insert-and-return-a-basic-document-without-id-and-with-default-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}
result (mc/insert-and-return :people doc)]
(is (= (:name doc)
(:name result)))
(is (= (:age doc)
(:age result)))
(is (:_id result))
(is (= 1 (mc/count collection)))))
(deftest insert-a-basic-document-without-id-and-with-default-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}]
(is (mc/insert db collection doc))
(is (= 1 (mc/count db collection)))))
(deftest insert-and-return-a-basic-document-without-id-but-with-a-write-concern
(let [collection "people"
doc {:name "Joe" :age 30 :ratio 3/4}
result (mc/insert-and-return "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-a-basic-document-with-explicitly-passed-database-without-id-and-with-default-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}]
(dotimes [n 5]
(mc/insert db collection doc WriteConcern/SAFE))
(is (= 5 (mc/count db collection)))))
(deftest insert-and-return-with-a-provided-id
(let [collection "people"
oid (ObjectId.)
doc {:name "Joe" :age 30 :_id oid}
result (mc/insert-and-return :people doc)]
(is (= (:_id result) (:_id doc) oid))
(is (= 1 (mc/count collection)))))
(deftest insert-a-basic-document-without-id-and-with-explicit-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}]
(is (mc/insert db collection doc WriteConcern/SAFE))
(is (= 1 (mc/count db collection)))))
(deftest insert-a-basic-db-object-without-id-and-with-default-write-concern
(let [collection "people"
doc (to-db-object {:name "Joe" :age 30})]
(is (nil? (.get ^DBObject doc "_id")))
(mc/insert db collection doc)
(is (not (nil? (monger.util/get-id doc))))))
(deftest insert-a-map-with-id-and-with-default-write-concern
(let [collection "people"
id (ObjectId.)
doc {:name "Joe" :age 30 "_id" id}
result (mc/insert db collection doc)]
(is (= id (monger.util/get-id doc)))))
(deftest insert-a-document-with-clojure-ratio-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:ratio 11/2 "_id" id}
result (mc/insert db collection doc)]
(is (= 5.5 (:ratio (mc/find-map-by-id db collection id))))))
(deftest insert-a-document-with-clojure-keyword-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:keyword :kwd "_id" id}
result (mc/insert db collection 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 [collection "widgets"
id (ObjectId.)
doc {:keyword1 {:keyword2 #{:kw1 :kw2}} "_id" id}
result (mc/insert db collection doc)]
(is (= (sort ["kw1" "kw2"])
(sort (get-in (mc/find-map-by-id db collection id) [:keyword1 :keyword2]))))))
(deftest insert-a-document-with-clojure-record-in-it
(let [collection "widgets"
id (ObjectId.)
doc {:record (Metrics. 10 20) "_id" id}
result (mc/insert db collection doc)]
(is (= {:rps 10 :eps 20} (:record (mc/find-map-by-id db collection id))))))
;; TODO: disabled until we figure out how to implement dereferencing of DBRefs
;; in 3.0 in a compatible way (and if that's possible at all). MK.
#_ (deftest test-insert-a-document-with-dbref
(mc/remove db "widgets")
(mc/remove db "owners")
(let [coll1 "widgets"
coll2 "owners"
oid (ObjectId.)
joe (mc/insert db coll2 {:name "Joe" :_id oid})
dbref (DBRef. coll2 oid)]
(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))))))
;;
;; insert-batch
;;
;;
;; insert-and-return
;;
(deftest insert-a-batch-of-basic-documents-without-ids-and-with-default-write-concern
(let [collection "people"
docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]]
(is (monger.result/ok? (mc/insert-batch "people" docs)))
(is (= 2 (mc/count collection)))))
(deftest insert-and-return-a-basic-document-without-id-and-with-default-write-concern
(let [collection "people"
doc {:name "Joe" :age 30}
result (mc/insert-and-return db collection doc)]
(is (= (:name doc)
(:name result)))
(is (= (:age doc)
(:age result)))
(is (:_id result))
(is (= 1 (mc/count db collection)))))
(deftest insert-a-batch-of-basic-documents-without-ids-and-with-explicit-write-concern
(let [collection "people"
docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]]
(is (monger.result/ok? (mc/insert-batch "people" docs WriteConcern/NORMAL)))
(is (= 2 (mc/count collection)))))
(deftest insert-and-return-a-basic-document-without-id-but-with-a-write-concern
(let [collection "people"
doc {:name "Joe" :age 30 :ratio 3/4}
result (mc/insert-and-return db collection 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 db collection)))))
(deftest insert-a-batch-of-basic-documents-with-explicit-database-without-ids-and-with-explicit-write-concern
(let [collection "people"
docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]]
(dotimes [n 44]
(is (monger.result/ok? (mc/insert-batch monger.core/*mongodb-database* "people" docs WriteConcern/NORMAL))))
(is (= 88 (mc/count collection)))))
(deftest insert-and-return-with-a-provided-id
(let [collection "people"
oid (ObjectId.)
doc {:name "Joe" :age 30 :_id oid}
result (mc/insert-and-return db collection doc)]
(is (= (:_id result) (:_id doc) oid))
(is (= 1 (mc/count db collection)))))
;;
;; insert-batch
;;
(deftest insert-a-batch-of-basic-documents-without-ids-and-with-default-write-concern
(let [collection "people"
docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]]
(is (mc/insert-batch db collection docs))
(is (= 2 (mc/count db collection)))))
(deftest insert-a-batch-of-basic-documents-without-ids-and-with-explicit-write-concern
(let [collection "people"
docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]]
(is (mc/insert-batch db collection docs WriteConcern/FSYNCED))
(is (= 2 (mc/count db collection)))))
(deftest insert-a-batch-of-basic-documents-with-explicit-database-without-ids-and-with-explicit-write-concern
(let [collection "people"
docs [{:name "Joe" :age 30} {:name "Paul" :age 27}]]
(dotimes [n 44]
(is (mc/insert-batch db collection docs WriteConcern/FSYNCED)))
(is (= 88 (mc/count db collection)))))
(deftest insert-a-batch-of-basic-documents-from-a-lazy-sequence
(let [collection "people"
numbers (range 0 1000)]
(is (mc/insert-batch db collection (map (fn [^long l]
{:n l})
numbers)))
(is (= (count numbers) (mc/count db collection))))))

View file

@ -1,45 +0,0 @@
(ns monger.test.internal.fn-test
(:use clojure.test
monger.internal.fn))
(deftest test-expand-all
(are [i o] (is (= (expand-all i) o))
{ :int (fn [] 1) :str "Clojure" :float (Float/valueOf 11.0) } { :int 1 :str "Clojure" :float (Float/valueOf 11.0 )}
{ :long (fn [] (Long/valueOf 11)) } { :long (Long/valueOf 11) }
{
:i 1
:l (Long/valueOf 1111)
:s "Clojure"
:d (Double/valueOf 11.1)
:f (Float/valueOf 2.5)
:v [1 2 3]
:dyn-v [(fn [] 10) (fn [] 20) (fn [] 30)]
:dyn-i (fn [] 1)
:dyn-s (fn [] "Clojure (expanded)")
:m { :nested "String" }
:dyn-m { :abc (fn [] :abc) :nested { :a { :b { :c (fn [] "d") } } } }
}
{
:i 1
:l (Long/valueOf 1111)
:s "Clojure"
:d (Double/valueOf 11.1)
:f (Float/valueOf 2.5)
:v [1 2 3]
:dyn-v [10 20 30]
:dyn-i 1
:dyn-s "Clojure (expanded)"
:m { :nested "String" }
:dyn-m {
:abc :abc
:nested { :a { :b { :c "d" } } }
}
}))
(deftest test-expand-all-with
(let [expander-fn (fn [f]
(* 3 (f)))]
(are [i o] (is (= (expand-all-with i expander-fn) o))
{ :a 1 :int (fn [] 3) } { :a 1 :int 9 }
{ :v [(fn [] 1) (fn [] 11)] :m { :inner (fn [] 3) } :s "Clojure" } { :v [3 33] :m { :inner 9 } :s "Clojure" })))

View file

@ -1,6 +1,6 @@
(ns monger.test.internal.pagination-test
(:use clojure.test
monger.internal.pagination))
(:require [clojure.test :refer :all]
[monger.internal.pagination :refer :all]))
(deftest test-pagination-offset
(are [a b] (= a b)

View file

@ -1,9 +1,6 @@
(ns monger.test.js-test
(:require monger.js
[monger.test.helper :as helper])
(:use clojure.test))
(helper/connect!)
[clojure.test :refer :all]))
(deftest load-js-resource-using-path-on-the-classpath
(are [c path] (= c (count (monger.js/load-resource path)))

View file

@ -0,0 +1,16 @@
(ns monger.test.json-cheshire-test
(:require [clojure.test :refer :all]
[monger.json]
[cheshire.core :refer :all])
(:import org.bson.types.ObjectId
org.bson.types.BSONTimestamp))
(deftest convert-dbobject-to-json
(let [input (ObjectId.)
output (generate-string input)]
(is (= (str "\"" input "\"") output))))
(deftest convert-bson-timestamp-to-json
(let [input (BSONTimestamp. 123 4)
output (generate-string input)]
(is (= "{\"time\":123,\"inc\":4}" output))))

View file

@ -0,0 +1,16 @@
(ns monger.test.json-test
(:require [clojure.test :refer :all]
[monger.json]
[clojure.data.json :as json])
(:import org.bson.types.ObjectId
org.bson.types.BSONTimestamp))
(deftest convert-dbobject-to-json
(let [input (ObjectId.)
output (json/write-str input)]
(is (= (str "\"" input "\"") output))))
(deftest convert-bson-timestamp-to-json
(let [input (BSONTimestamp. 123 4)
output (json/write-str input)]
(is (= "{\"time\":123,\"inc\":4}" output))))

View file

@ -1,42 +1,55 @@
(ns monger.test.lib-integration-test
(:use clojure.test
monger.json
monger.joda-time
monger.conversion)
(:import [org.joda.time DateTime DateMidnight]
(:import [org.joda.time DateTime DateMidnight LocalDate]
org.bson.types.ObjectId
com.mongodb.DBObject)
(:require [clojure.data.json :as json]
[clj-time.core :as t]))
(:require monger.json
monger.joda-time
[clj-time.core :as t]
[cheshire.core :as json]
[clojure.test :refer :all]
[monger.conversion :refer :all]))
(deftest serialization-of-joda-datetime-to-json-with-clojure-data-json
(is (= "\"2011-10-13T23:55:00.000Z\"" (json/json-str (t/date-time 2011 10 13 23 55 0)))))
(deftest ^{:integration true} serialization-of-joda-datetime-to-json
(let [dt (t/date-time 2011 10 13 23 55 0)]
(is (= "\"2011-10-13T23:55:00.000Z\""
(json/encode dt)))))
(deftest serialization-of-object-id-to-json-with-clojure-data-json
(is (= "\"4ec2d1a6b55634a935ea4ac8\"" (json/json-str (ObjectId. "4ec2d1a6b55634a935ea4ac8")))))
(deftest ^{:integration true} serialization-of-joda-date-to-json
(let [d (.toDate (t/date-time 2011 10 13 23 55 0))]
(is (= "\"2011-10-13T23:55:00Z\""
(json/encode d)))))
(deftest conversion-of-joda-datetime-to-db-object
(deftest ^{:integration true} conversion-of-joda-datetime-to-db-object
(let [d (to-db-object (t/date-time 2011 10 13 23 55 0))]
(is (instance? java.util.Date d))
(is (= 1318550100000 (.getTime ^java.util.Date d)))))
(deftest conversion-of-joda-datemidnight-to-db-object
(deftest ^{:integration true} conversion-of-joda-datemidnight-to-db-object
(let [d (to-db-object (DateMidnight. (t/date-time 2011 10 13)))]
(is (instance? java.util.Date d))
(is (= 1318464000000 (.getTime ^java.util.Date d)))))
(deftest ^{:integration true} conversion-of-joda-localdate-to-db-object
(let [d (to-db-object (LocalDate. 2011 10 13))]
(is (instance? java.util.Date d))
(is (= 111 (.getYear ^java.util.Date d))) ;; how many years since 1900
(is (= 9 (.getMonth ^java.util.Date d))) ;; java.util.Date counts from 0
(is (= 13 (.getDate ^java.util.Date d)))))
(deftest conversion-of-java-util-date-to-joda-datetime
(deftest ^{:integration true} conversion-of-java-util-date-to-joda-datetime
(let [input (.toDate ^DateTime (t/date-time 2011 10 13 23 55 0))
output (from-db-object input false)]
(is (instance? org.joda.time.DateTime output))
(is (= input (.toDate ^DateTime output)))))
(deftest test-reader-extensions
(deftest ^{:integration true} test-reader-extensions
(let [^DateTime d (t/date-time 2011 10 13 23 55 0)]
(binding [*print-dup* true]
(pr-str d))))
(deftest ^{:integration true} test-reader-extensions-for-localdate
(let [^DateTime d (t/today)]
(binding [*print-dup* true]
(pr-str d))))

View file

@ -1,69 +0,0 @@
(ns monger.test.map-reduce-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure MapReduceOutput MapReduceCommand MapReduceCommand$OutputType]
org.bson.types.ObjectId
java.util.Date)
(:require [monger core util]
[monger.collection :as mc]
[monger.result :as mgres]
[clojurewerkz.support.js :as js]
[monger.test.helper :as helper])
(:use clojure.test
[monger operators conversion]
monger.test.fixtures))
(helper/connect!)
(use-fixtures :each purge-people purge-docs purge-things purge-libraries)
;;
;; Map/Reduce
;;
(let [collection "widgets"
mapper (js/load-resource "resources/mongo/js/mapfun1.js")
reducer "function(key, values) {
var result = 0;
values.forEach(function(v) { result += v });
return result;
}"
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 }]
expected [{:_id "CA", :value 204.9} {:_id "IL", :value 39.5} {:_id "NY", :value 697.0}]]
(deftest test-basic-inline-map-reduce-example
(mc/remove monger.core/*mongodb-database* collection {})
(is (mgres/ok? (mc/insert-batch collection batch)))
(let [output (mc/map-reduce collection mapper reducer nil MapReduceCommand$OutputType/INLINE {})
results (from-db-object ^DBObject (.results ^MapReduceOutput output) true)]
(mgres/ok? output)
(is (= expected results))))
(deftest test-basic-map-reduce-example-that-replaces-named-collection
(mc/remove monger.core/*mongodb-database* collection {})
(is (mgres/ok? (mc/insert-batch collection batch)))
(let [output (mc/map-reduce collection mapper reducer "mr_outputs" {})
results (from-db-object ^DBObject (.results ^MapReduceOutput output) true)]
(mgres/ok? output)
(is (= 3 (monger.core/count results)))
(is (= expected
(map #(from-db-object % true) (seq results))))
(is (= expected
(map #(from-db-object % true) (mc/find "mr_outputs"))))
(.drop ^MapReduceOutput output)))
(deftest test-basic-map-reduce-example-that-merged-results-into-named-collection
(mc/remove monger.core/*mongodb-database* collection {})
(is (mgres/ok? (mc/insert-batch collection batch)))
(mc/map-reduce collection mapper reducer "merged_mr_outputs" MapReduceCommand$OutputType/MERGE {})
(is (mgres/ok? (mc/insert collection { :state "OR" :price 17.95 :quantity 4 })))
(let [^MapReduceOutput output (mc/map-reduce collection mapper reducer "merged_mr_outputs" MapReduceCommand$OutputType/MERGE {})]
(mgres/ok? output)
(is (= 4 (monger.core/count output)))
(is (= ["CA" "IL" "NY" "OR"]
(map :_id (mc/find-maps "merged_mr_outputs"))))
(.drop ^MapReduceOutput output))))

View file

@ -1,111 +1,146 @@
(set! *warn-on-reflection* true)
(ns monger.test.query-operators-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure MapReduceOutput MapReduceCommand MapReduceCommand$OutputType]
org.bson.types.ObjectId
java.util.Date)
(:require [monger core util]
[clojure stacktrace]
[monger.collection :as mgcol]
[monger.result :as mgres]
[monger.conversion :as mgcnv]
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.js :as js]
[monger.test.helper :as helper])
(:use [clojure.test]
[monger.operators]
[monger.test.fixtures]))
[clojure.test :refer :all]
[clojure.set :refer [difference]]
[monger.operators :refer :all])
(:import [com.mongodb QueryOperators]))
(monger.core/connect!)
(monger.core/set-db! (monger.core/get-db "monger-test"))
;; (use-fixtures :each purge-people purge-docs purge-things purge-libraries)
(use-fixtures :each purge-people purge-docs purge-things purge-libraries)
(deftest every-query-operator-is-defined
(let [driver-query-operators (->> (.getDeclaredFields QueryOperators) (map #(.get % nil)) set)
monger-query-operators (->> (ns-publics 'monger.operators) (map (comp name first)) set)
; $within is deprecated and replaced by $geoWithin since v2.4.
; $uniqueDocs is deprecated since v2.6.
deprecated-query-operators #{"$within" "$uniqueDocs"}
; Query modifier operators that are deprecated in the mongo shell since v3.2
deprecated-meta-operators #{"$comment" "$explain" "$hint" "$maxScan"
"$maxTimeMS" "$max" "$min" "$orderby"
"$returnKey" "$showDiskLoc" "$snapshot" "$query"}
undefined-non-deprecated-operators (difference driver-query-operators
deprecated-query-operators
deprecated-meta-operators
monger-query-operators)]
(is (= #{} undefined-non-deprecated-operators))))
;;
;; $gt, $gte, $lt, lte
;;
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-collections
[f]
(mc/remove db "people")
(mc/remove db "libraries")
(f)
(mc/remove db "people")
(mc/remove db "libraries"))
(deftest find-with-conditional-operators-comparison
(let [collection "libraries"]
(mgcol/insert-batch collection [{:language "Clojure" :name "monger" :users 1}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(are [a b] (= a (.count (mgcol/find collection b)))
2 {:users {$gt 10}}
3 {:users {$gte 5}}
2 {:users {$lt 10}}
2 {:users {$lte 5}}
1 {:users {$gt 10 $lt 150}})))
(use-fixtures :each purge-collections)
;;
;; $ne
;;
;;
;; $gt, $gte, $lt, lte
;;
(deftest find-with-and-or-operators
(let [collection "libraries"]
(mgcol/insert-batch collection [{:language "Ruby" :name "mongoid" :users 1}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(is (= 2 (.count (mgcol/find collection {$ne {:language "Clojure"}}))))))
(deftest find-with-conditional-operators-comparison
(let [collection "libraries"]
(mc/insert-batch db collection [{:language "Clojure" :name "monger" :users 1}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(are [a b] (= a (.count (mc/find db collection b)))
2 {:users {$gt 10}}
3 {:users {$gte 5}}
2 {:users {$lt 10}}
2 {:users {$lte 5}}
1 {:users {$gt 10 $lt 150}})))
;;
;; $eq
;;
(deftest find-with-eq-operator
(let [collection "libraries"]
(mc/insert-batch db collection [{:language "Ruby" :name "mongoid" :users 1 :displayName nil}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(is (= 2 (.count (mc/find db collection {:language {$eq "Clojure"}}))))))
;;
;; $ne
;;
(deftest find-with-ne-operator
(let [collection "libraries"]
(mc/insert-batch db collection [{:language "Ruby" :name "mongoid" :users 1}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(is (= 2 (.count (mc/find db collection {:language {$ne "Clojure"}}))))))
;;
;; $and, $or, $nor
;;
;;
;; $and, $or, $nor
;;
(deftest find-with-and-or-operators
(let [collection "libraries"]
(mgcol/insert-batch collection [{:language "Ruby" :name "mongoid" :users 1}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(is (= 1 (.count (mgcol/find collection {$and [{:language "Clojure"}
{:users {$gt 10}}]}))))
(is (= 3 (.count (mgcol/find collection {$or [{:language "Clojure"}
{:users {$gt 10}} ]}))))
(is (= 1 (.count (mgcol/find collection {$nor [{:language "Clojure"}
{:users {$gt 10}} ]}))))))
(deftest find-with-and-or-operators
(let [collection "libraries"]
(mc/insert-batch db collection [{:language "Ruby" :name "mongoid" :users 1}
{:language "Clojure" :name "langohr" :users 5}
{:language "Clojure" :name "incanter" :users 15}
{:language "Scala" :name "akka" :users 150}])
(is (= 1 (.count (mc/find db collection {$and [{:language "Clojure"}
{:users {$gt 10}}]}))))
(is (= 3 (.count (mc/find db collection {$or [{:language "Clojure"}
{:users {$gt 10}} ]}))))
(is (= 1 (.count (mc/find db collection {$nor [{:language "Clojure"}
{:users {$gt 10}} ]}))))))
;;
;; $all, $in, $nin
;;
;;
;; $all, $in, $nin
;;
(deftest find-on-embedded-arrays
(let [collection "libraries"]
(mgcol/insert-batch collection [{:language "Clojure" :tags [ "functional" ]}
{:language "Scala" :tags [ "functional" "object-oriented" ]}
{:language "Ruby" :tags [ "object-oriented" "dynamic" ]}])
(deftest find-on-embedded-arrays
(let [collection "libraries"]
(mc/insert-batch db collection [{:language "Clojure" :tags [ "functional" ]}
{:language "Scala" :tags [ "functional" "object-oriented" ]}
{:language "Ruby" :tags [ "object-oriented" "dynamic" ]}])
(is (= "Scala" (:language (first (mgcol/find-maps collection {:tags {$all [ "functional" "object-oriented" ]}} )))))
(is (= 3 (.count (mgcol/find-maps collection {:tags {$in [ "functional" "object-oriented" ]}} ))))
(is (= 2 (.count (mgcol/find-maps collection {:language {$in [ "Scala" "Ruby" ]}} ))))
(is (= 1 (.count (mgcol/find-maps collection {:tags {$nin [ "dynamic" "object-oriented" ]}} ))))
(is (= 3 (.count (mgcol/find-maps collection {:language {$nin [ "C#" ]}} ))))))
(is (= "Scala" (:language (first (mc/find-maps db collection {:tags {$all [ "functional" "object-oriented" ]}} )))))
(is (= 3 (.count (mc/find-maps db collection {:tags {$in [ "functional" "object-oriented" ]}} ))))
(is (= 2 (.count (mc/find-maps db collection {:language {$in [ "Scala" "Ruby" ]}} ))))
(is (= 1 (.count (mc/find-maps db collection {:tags {$nin [ "dynamic" "object-oriented" ]}} ))))
(is (= 3 (.count (mc/find-maps db collection {:language {$nin [ "C#" ]}} ))))))
(deftest find-with-conditional-operators-on-embedded-documents
(let [collection "people"]
(mgcol/insert-batch collection [{:name "Bob" :comments [{:text "Nice!" :rating 1}
{:text "Love it" :rating 4}
{:text "What?":rating -5} ]}
{:name "Alice" :comments [{:text "Yeah" :rating 2}
{:text "Doh" :rating 1}
{:text "Agreed" :rating 3}]}])
(are [a b] (= a (.count (mgcol/find collection b)))
1 {:comments {$elemMatch {:text "Nice!" :rating {$gte 1}}}}
2 {"comments.rating" 1}
1 {"comments.rating" {$gt 3}})))
(deftest find-with-conditional-operators-on-embedded-documents
(let [collection "people"]
(mc/insert-batch db collection [{:name "Bob" :comments [{:text "Nice!" :rating 1}
{:text "Love it" :rating 4}
{:text "What?":rating -5} ]}
{:name "Alice" :comments [{:text "Yeah" :rating 2}
{:text "Doh" :rating 1}
{:text "Agreed" :rating 3}]}])
(are [a b] (= a (.count (mc/find db collection b)))
1 {:comments {$elemMatch {:text "Nice!" :rating {$gte 1}}}}
2 {"comments.rating" 1}
1 {"comments.rating" {$gt 3}})))
(deftest find-with-regex-operator
(let [collection "libraries"]
(mgcol/insert-batch collection [{:language "Ruby" :name "Mongoid" :users 1}
{:language "Clojure" :name "Langohr" :users 5}
{:language "Clojure" :name "Incanter" :users 15}
{:language "Scala" :name "Akka" :users 150}])
(are [query results] (is (= results (.count (mgcol/find collection query))))
{:language {$regex "Clo.*"}} 2
{:language {$regex "clo.*" $options "i"}} 2
{:name {$regex "aK.*" $options "i"}} 1
{:language {$regex ".*by"}} 1
{:language {$regex ".*ala.*"}} 1)))
(deftest find-with-regex-operator
(let [collection "libraries"]
(mc/insert-batch db collection [{:language "Ruby" :name "Mongoid" :users 1}
{:language "Clojure" :name "Langohr" :users 5}
{:language "Clojure" :name "Incanter" :users 15}
{:language "Scala" :name "Akka" :users 150}])
(are [query results] (is (= results (.count (mc/find db collection query))))
{:language {$regex "Clo.*"}} 2
{:language {$regex "clo.*" $options "i"}} 2
{:name {$regex "aK.*" $options "i"}} 1
{:language {$regex ".*by"}} 1
{:language {$regex ".*ala.*"}} 1)))
(deftest find-with-js-expression
(let [collection "people"]
(mc/insert-batch db collection [{:name "Bob" :placeOfBirth "New York" :address {:city "New York"}}
{:name "Alice" :placeOfBirth "New York" :address {:city "Los Angeles"}}])
(is (= 1 (.count (mc/find db collection {$where "this.placeOfBirth === this.address.city"})))))))

View file

@ -1,288 +1,325 @@
(set! *warn-on-reflection* true)
(ns monger.test.querying-test
(:refer-clojure :exclude [select find sort])
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure ReadPreference]
(:import [com.mongodb WriteResult WriteConcern DBObject ReadPreference]
org.bson.types.ObjectId
java.util.Date)
(:require [monger core util]
[monger.collection :as mgcol]
(:require [monger.core :as mg]
[monger.collection :as mc]
monger.joda-time
[monger.result :as mgres]
[monger.test.helper :as helper])
(:use clojure.test
monger.test.fixtures
[monger conversion query operators joda-time]
[clj-time.core :only [date-time]]))
[clojure.test :refer :all]
[monger.conversion :refer :all]
[monger.query :refer :all]
[monger.operators :refer :all]
[clj-time.core :refer [date-time]]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(use-fixtures :each purge-docs purge-things purge-locations)
(defn purge-collections
[f]
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "locations")
(mc/remove db "querying_docs")
(f)
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "locations")
(mc/remove db "querying_docs"))
(use-fixtures :each purge-collections)
;;
;; monger.collection/* finders ("low-level API")
;;
;; by ObjectId
(deftest query-full-document-by-object-id
(let [coll "querying_docs"
oid (ObjectId.)
doc { :_id oid :title "Introducing Monger" }]
(mc/insert db coll doc)
(is (= doc (mc/find-map-by-id db coll oid)))
(is (= doc (mc/find-one-as-map db coll { :_id oid })))))
;;
;; monger.collection/* finders ("low-level API")
;;
;; exact match over string field
;; by ObjectId
(deftest query-full-document-by-object-id
(let [coll "docs"
oid (ObjectId.)
doc { :_id oid :title "Introducing Monger" }]
(mgcol/insert coll doc)
(is (= doc (mgcol/find-map-by-id coll oid)))
(is (= doc (mgcol/find-one-as-map coll { :_id oid })))))
(deftest query-full-document-using-exact-matching-over-string-field
(let [coll "querying_docs"
doc { :title "monger" :language "Clojure" :_id (ObjectId.) }]
(mc/insert db coll doc)
(is (= [doc] (mc/find-maps db coll { :title "monger" })))
(is (= doc (from-db-object (first (mc/find db coll { :title "monger" })) true)))))
;; exact match over string field
;; exact match over string field with limit
(deftest query-full-document-using-exact-matching-over-string-field
(let [coll "docs"
doc { :title "monger" :language "Clojure" :_id (ObjectId.) }]
(mgcol/insert coll doc)
(is (= [doc] (mgcol/find-maps coll { :title "monger" })))
(is (= doc (from-db-object (first (mgcol/find coll { :title "monger" })) true)))))
(deftest query-full-document-using-exact-matching-over-string-with-field-with-limit
(let [coll "querying_docs"
doc1 { :title "monger" :language "Clojure" :_id (ObjectId.) }
doc2 { :title "langohr" :language "Clojure" :_id (ObjectId.) }
doc3 { :title "netty" :language "Java" :_id (ObjectId.) }
_ (mc/insert-batch db coll [doc1 doc2 doc3])
result (with-collection db coll
(find { :title "monger" })
(fields [:title, :language, :_id])
(skip 0)
(limit 1))]
(is (= 1 (count result)))
(is (= [doc1] result))))
;; exact match over string field with limit
(deftest query-full-document-using-exact-matching-over-string-field-with-limit-and-offset
(let [coll "querying_docs"
doc1 { :title "lucene" :language "Java" :_id (ObjectId.) }
doc2 { :title "joda-time" :language "Java" :_id (ObjectId.) }
doc3 { :title "netty" :language "Java" :_id (ObjectId.) }
_ (mc/insert-batch db coll [doc1 doc2 doc3])
result (with-collection db coll
(find { :language "Java" })
(skip 1)
(limit 2)
(sort { :title 1 }))]
(is (= 2 (count result)))
(is (= [doc1 doc3] result))))
(deftest query-full-document-using-exact-matching-over-string-with-field-with-limit
(let [coll "docs"
doc1 { :title "monger" :language "Clojure" :_id (ObjectId.) }
doc2 { :title "langohr" :language "Clojure" :_id (ObjectId.) }
doc3 { :title "netty" :language "Java" :_id (ObjectId.) }
_ (mgcol/insert-batch coll [doc1 doc2 doc3])
result (with-collection coll
(find { :title "monger" })
(fields [:title, :language, :_id])
(skip 0)
(limit 1))]
(is (= 1 (count result)))
(is (= [doc1] result))))
(deftest query-with-sorting-on-multiple-fields
(let [coll "querying_docs"
doc1 { :a 1 :b 2 :c 3 :text "Whatever" :_id (ObjectId.) }
doc2 { :a 1 :b 1 :c 4 :text "Blah " :_id (ObjectId.) }
doc3 { :a 10 :b 3 :c 1 :text "Abc" :_id (ObjectId.) }
doc4 { :a 10 :b 3 :c 3 :text "Abc" :_id (ObjectId.) }
_ (mc/insert-batch db coll [doc1 doc2 doc3 doc4])
result1 (with-collection db coll
(find {})
(limit 2)
(fields [:a :b :c :text])
(sort (sorted-map :a 1 :b 1 :text -1)))
result2 (with-collection db coll
(find {})
(limit 2)
(fields [:a :b :c :text])
(sort (array-map :c 1 :text -1)))
result3 (with-collection db coll
(find {})
(limit 2)
(fields [:a :b :c :text])
(sort (array-map :c -1 :text 1)))]
(is (= [doc2 doc1] result1))
(is (= [doc3 doc1] result2))
(is (= [doc2 doc4] result3))))
(deftest query-full-document-using-exact-matching-over-string-field-with-limit-and-offset
(let [coll "docs"
doc1 { :title "lucene" :language "Java" :_id (ObjectId.) }
doc2 { :title "joda-time" :language "Java" :_id (ObjectId.) }
doc3 { :title "netty" :language "Java" :_id (ObjectId.) }
_ (mgcol/insert-batch coll [doc1 doc2 doc3])
result (with-collection coll
(find { :language "Java" })
(skip 1)
(limit 2)
(sort { :title 1 }))]
(is (= 2 (count result)))
(is (= [doc1 doc3] result))))
;; < ($lt), <= ($lte), > ($gt), >= ($gte)
(deftest query-using-dsl-and-$lt-operator-with-integers
(let [coll "querying_docs"
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year 2006 }
doc2 { :language "Java" :_id (ObjectId.) :inception_year 1992 }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year 2003 }
_ (mc/insert-batch db coll [doc1 doc2])
lt-result (with-collection db coll
(find { :inception_year { $lt 2000 } })
(limit 2))]
(is (= [doc2] (vec lt-result)))))
;; < ($lt), <= ($lte), > ($gt), >= ($gte)
(deftest query-using-dsl-and-$lt-operator-with-dates
(let [coll "querying_docs"
;; these rely on monger.joda-time being loaded. MK.
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year (date-time 2006 1 1) }
doc2 { :language "Java" :_id (ObjectId.) :inception_year (date-time 1992 1 2) }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year (date-time 2003 3 3) }
_ (mc/insert-batch db coll [doc1 doc2])
lt-result (with-collection db coll
(find { :inception_year { $lt (date-time 2000 1 2) } })
(limit 2))]
(is (= (map :_id [doc2])
(map :_id (vec lt-result))))))
(deftest query-using-dsl-and-$lt-operator-with-integers
(let [coll "docs"
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year 2006 }
doc2 { :language "Java" :_id (ObjectId.) :inception_year 1992 }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year 2003 }
_ (mgcol/insert-batch coll [doc1 doc2])
lt-result (with-collection "docs"
(find { :inception_year { $lt 2000 } })
(limit 2))]
(is (= [doc2] (vec lt-result)))))
(deftest query-using-both-$lte-and-$gte-operators-with-dates
(let [coll "querying_docs"
;; these rely on monger.joda-time being loaded. MK.
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year (date-time 2006 1 1) }
doc2 { :language "Java" :_id (ObjectId.) :inception_year (date-time 1992 1 2) }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year (date-time 2003 3 3) }
_ (mc/insert-batch db coll [doc1 doc2 doc3])
lt-result (with-collection db coll
(find { :inception_year { $gt (date-time 2000 1 2) $lte (date-time 2007 2 2) } })
(sort { :inception_year 1 }))]
(is (= (map :_id [doc3 doc1])
(map :_id (vec lt-result))))))
(deftest query-using-dsl-and-$lt-operator-with-dates
(let [coll "docs"
;; these rely on monger.joda-time being loaded. MK.
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year (date-time 2006 1 1) }
doc2 { :language "Java" :_id (ObjectId.) :inception_year (date-time 1992 1 2) }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year (date-time 2003 3 3) }
_ (mgcol/insert-batch coll [doc1 doc2])
lt-result (with-collection "docs"
(find { :inception_year { $lt (date-time 2000 1 2) } })
(limit 2))]
(is (= (map :_id [doc2])
(map :_id (vec lt-result))))))
(deftest query-using-both-$lte-and-$gte-operators-with-dates
(let [coll "docs"
;; these rely on monger.joda-time being loaded. MK.
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year (date-time 2006 1 1) }
doc2 { :language "Java" :_id (ObjectId.) :inception_year (date-time 1992 1 2) }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year (date-time 2003 3 3) }
_ (mgcol/insert-batch coll [doc1 doc2 doc3])
lt-result (with-collection "docs"
(find { :inception_year { $gt (date-time 2000 1 2) $lte (date-time 2007 2 2) } })
(sort { :inception_year 1 }))]
(is (= (map :_id [doc3 doc1])
(map :_id (vec lt-result))))))
(deftest query-using-$gt-$lt-$gte-$lte-operators-as-strings
(let [coll "querying_docs"
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year 2006 }
doc2 { :language "Java" :_id (ObjectId.) :inception_year 1992 }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year 2003 }
_ (mc/insert-batch db coll [doc1 doc2 doc3])]
(are [doc, result]
(= doc, result)
(doc2 (with-collection db coll
(find { :inception_year { "$lt" 2000 } })))
(doc2 (with-collection db coll
(find { :inception_year { "$lte" 1992 } })))
(doc1 (with-collection db coll
(find { :inception_year { "$gt" 2002 } })
(limit 1)
(sort { :inception_year -1 })))
(doc1 (with-collection db coll
(find { :inception_year { "$gte" 2006 } }))))))
(deftest query-using-$gt-$lt-$gte-$lte-operators-as-strings
(let [coll "docs"
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year 2006 }
doc2 { :language "Java" :_id (ObjectId.) :inception_year 1992 }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year 2003 }
_ (mgcol/insert-batch coll [doc1 doc2 doc3])]
(are [doc, result]
(= doc, result)
(doc2 (with-collection coll
(find { :inception_year { "$lt" 2000 } })))
(doc2 (with-collection coll
(find { :inception_year { "$lte" 1992 } })))
(doc1 (with-collection coll
(find { :inception_year { "$gt" 2002 } })
(limit 1)
(sort { :inception_year -1 })))
(doc1 (with-collection coll
(find { :inception_year { "$gte" 2006 } }))))))
(deftest query-using-$gt-$lt-$gte-$lte-operators-using-dsl-composition
(let [coll "querying_docs"
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year 2006 }
doc2 { :language "Java" :_id (ObjectId.) :inception_year 1992 }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year 2003 }
srt (-> {}
(limit 1)
(sort { :inception_year -1 }))
_ (mc/insert-batch db coll [doc1 doc2 doc3])]
(is (= [doc1] (with-collection db coll
(find { :inception_year { "$gt" 2002 } })
(merge srt))))))
(deftest query-using-$gt-$lt-$gte-$lte-operators-using-dsl-composition
(let [coll "docs"
doc1 { :language "Clojure" :_id (ObjectId.) :inception_year 2006 }
doc2 { :language "Java" :_id (ObjectId.) :inception_year 1992 }
doc3 { :language "Scala" :_id (ObjectId.) :inception_year 2003 }
srt (-> {}
(limit 1)
(sort { :inception_year -1 }))
_ (mgcol/insert-batch coll [doc1 doc2 doc3])]
(is (= [doc1] (with-collection coll
(find { :inception_year { "$gt" 2002 } })
(merge srt))))))
;; $all
(deftest query-with-using-$all
(let [coll "querying_docs"
doc1 { :_id (ObjectId.) :title "Clojure" :tags ["functional" "homoiconic" "syntax-oriented" "dsls" "concurrency features" "jvm"] }
doc2 { :_id (ObjectId.) :title "Java" :tags ["object-oriented" "jvm"] }
doc3 { :_id (ObjectId.) :title "Scala" :tags ["functional" "object-oriented" "dsls" "concurrency features" "jvm"] }
- (mc/insert-batch db coll [doc1 doc2 doc3])
result1 (with-collection db coll
(find { :tags { "$all" ["functional" "jvm" "homoiconic"] } }))
result2 (with-collection db coll
(find { :tags { "$all" ["functional" "native" "homoiconic"] } }))
result3 (with-collection db coll
(find { :tags { "$all" ["functional" "jvm" "dsls"] } })
(sort { :title 1 }))]
(is (= [doc1] result1))
(is (empty? result2))
(is (= 2 (count result3)))
(is (= doc1 (first result3)))))
;; $all
;; $exists
(deftest query-with-using-$all
(let [coll "docs"
doc1 { :_id (ObjectId.) :title "Clojure" :tags ["functional" "homoiconic" "syntax-oriented" "dsls" "concurrency features" "jvm"] }
doc2 { :_id (ObjectId.) :title "Java" :tags ["object-oriented" "jvm"] }
doc3 { :_id (ObjectId.) :title "Scala" :tags ["functional" "object-oriented" "dsls" "concurrency features" "jvm"] }
- (mgcol/insert-batch coll [doc1 doc2 doc3])
result1 (with-collection coll
(find { :tags { "$all" ["functional" "jvm" "homoiconic"] } }))
result2 (with-collection coll
(find { :tags { "$all" ["functional" "native" "homoiconic"] } }))
result3 (with-collection coll
(find { :tags { "$all" ["functional" "jvm" "dsls"] } })
(sort { :title 1 }))]
(is (= [doc1] result1))
(is (empty? result2))
(is (= 2 (count result3)))
(is (= doc1 (first result3)))))
(deftest query-with-find-one-as-map-using-$exists
(let [coll "querying_docs"
doc1 { :_id (ObjectId.) :published-by "Jill The Blogger" :draft false :title "X announces another Y" }
doc2 { :_id (ObjectId.) :draft true :title "Z announces a Y competitor" }
_ (mc/insert-batch db coll [doc1 doc2])
result1 (mc/find-one-as-map db coll { :published-by { "$exists" true } })
result2 (mc/find-one-as-map db coll { :published-by { "$exists" false } })]
(is (= doc1 result1))
(is (= doc2 result2))))
;; $mod
(deftest query-with-find-one-as-map-using-$mod
(let [coll "querying_docs"
doc1 { :_id (ObjectId.) :counter 25 }
doc2 { :_id (ObjectId.) :counter 32 }
doc3 { :_id (ObjectId.) :counter 63 }
_ (mc/insert-batch db coll [doc1 doc2 doc3])
result1 (mc/find-one-as-map db coll { :counter { "$mod" [10, 5] } })
result2 (mc/find-one-as-map db coll { :counter { "$mod" [10, 2] } })
result3 (mc/find-one-as-map db coll { :counter { "$mod" [11, 1] } })]
(is (= doc1 result1))
(is (= doc2 result2))
(is (empty? result3))))
;; $exists
;; $ne
(deftest query-with-find-one-as-map-using-$exists
(let [coll "docs"
doc1 { :_id (ObjectId.) :published-by "Jill The Blogger" :draft false :title "X announces another Y" }
doc2 { :_id (ObjectId.) :draft true :title "Z announces a Y competitor" }
_ (mgcol/insert-batch coll [doc1 doc2])
result1 (mgcol/find-one-as-map coll { :published-by { "$exists" true } })
result2 (mgcol/find-one-as-map coll { :published-by { "$exists" false } })]
(is (= doc1 result1))
(is (= doc2 result2))))
(deftest query-with-find-one-as-map-using-$ne
(let [coll "querying_docs"
doc1 { :_id (ObjectId.) :counter 25 }
doc2 { :_id (ObjectId.) :counter 32 }
_ (mc/insert-batch db coll [doc1 doc2])
result1 (mc/find-one-as-map db coll { :counter { "$ne" 25 } })
result2 (mc/find-one-as-map db coll { :counter { "$ne" 32 } })]
(is (= doc2 result1))
(is (= doc1 result2))))
;; $mod
;;
;; monger.query DSL features
;;
(deftest query-with-find-one-as-map-using-$mod
(let [coll "docs"
doc1 { :_id (ObjectId.) :counter 25 }
doc2 { :_id (ObjectId.) :counter 32 }
doc3 { :_id (ObjectId.) :counter 63 }
_ (mgcol/insert-batch coll [doc1 doc2 doc3])
result1 (mgcol/find-one-as-map coll { :counter { "$mod" [10, 5] } })
result2 (mgcol/find-one-as-map coll { :counter { "$mod" [10, 2] } })
result3 (mgcol/find-one-as-map coll { :counter { "$mod" [11, 1] } })]
(is (= doc1 result1))
(is (= doc2 result2))
(is (empty? result3))))
;; pagination
(deftest query-using-pagination-dsl
(let [coll "querying_docs"
doc1 { :_id (ObjectId.) :title "Clojure" :tags ["functional" "homoiconic" "syntax-oriented" "dsls" "concurrency features" "jvm"] }
doc2 { :_id (ObjectId.) :title "Java" :tags ["object-oriented" "jvm"] }
doc3 { :_id (ObjectId.) :title "Scala" :tags ["functional" "object-oriented" "dsls" "concurrency features" "jvm"] }
doc4 { :_id (ObjectId.) :title "Ruby" :tags ["dynamic" "object-oriented" "dsls" "jvm"] }
doc5 { :_id (ObjectId.) :title "Groovy" :tags ["dynamic" "object-oriented" "dsls" "jvm"] }
doc6 { :_id (ObjectId.) :title "OCaml" :tags ["functional" "static" "dsls"] }
doc7 { :_id (ObjectId.) :title "Haskell" :tags ["functional" "static" "dsls" "concurrency features"] }
- (mc/insert-batch db coll [doc1 doc2 doc3 doc4 doc5 doc6 doc7])
result1 (with-collection db coll
(find {})
(paginate :page 1 :per-page 3)
(sort { :title 1 })
(read-preference (ReadPreference/primary))
(options com.mongodb.Bytes/QUERYOPTION_NOTIMEOUT))
result2 (with-collection db coll
(find {})
(paginate :page 2 :per-page 3)
(sort { :title 1 }))
result3 (with-collection db coll
(find {})
(paginate :page 3 :per-page 3)
(sort { :title 1 }))
result4 (with-collection db coll
(find {})
(paginate :page 10 :per-page 3)
(sort { :title 1 }))]
(is (= [doc1 doc5 doc7] result1))
(is (= [doc2 doc6 doc4] result2))
(is (= [doc3] result3))
(is (empty? result4))))
;; $ne
(deftest combined-querying-dsl-example1
(let [coll "querying_docs"
ma-doc { :_id (ObjectId.) :name "Massachusetts" :iso "MA" :population 6547629 :joined_in 1788 :capital "Boston" }
de-doc { :_id (ObjectId.) :name "Delaware" :iso "DE" :population 897934 :joined_in 1787 :capital "Dover" }
ny-doc { :_id (ObjectId.) :name "New York" :iso "NY" :population 19378102 :joined_in 1788 :capital "Albany" }
ca-doc { :_id (ObjectId.) :name "California" :iso "CA" :population 37253956 :joined_in 1850 :capital "Sacramento" }
tx-doc { :_id (ObjectId.) :name "Texas" :iso "TX" :population 25145561 :joined_in 1845 :capital "Austin" }
top3 (partial-query (limit 3))
by-population-desc (partial-query (sort { :population -1 }))
_ (mc/insert-batch db coll [ma-doc de-doc ny-doc ca-doc tx-doc])
result (with-collection db coll
(find {})
(merge top3)
(merge by-population-desc))]
(is (= result [ca-doc tx-doc ny-doc]))))
(deftest query-with-find-one-as-map-using-$ne
(let [coll "docs"
doc1 { :_id (ObjectId.) :counter 25 }
doc2 { :_id (ObjectId.) :counter 32 }
_ (mgcol/insert-batch coll [doc1 doc2])
result1 (mgcol/find-one-as-map coll { :counter { "$ne" 25 } })
result2 (mgcol/find-one-as-map coll { :counter { "$ne" 32 } })]
(is (= doc2 result1))
(is (= doc1 result2))))
;;
;; monger.query DSL features
;;
;; pagination
(deftest query-using-pagination-dsl
(let [coll "docs"
doc1 { :_id (ObjectId.) :title "Clojure" :tags ["functional" "homoiconic" "syntax-oriented" "dsls" "concurrency features" "jvm"] }
doc2 { :_id (ObjectId.) :title "Java" :tags ["object-oriented" "jvm"] }
doc3 { :_id (ObjectId.) :title "Scala" :tags ["functional" "object-oriented" "dsls" "concurrency features" "jvm"] }
doc4 { :_id (ObjectId.) :title "Ruby" :tags ["dynamic" "object-oriented" "dsls" "jvm"] }
doc5 { :_id (ObjectId.) :title "Groovy" :tags ["dynamic" "object-oriented" "dsls" "jvm"] }
doc6 { :_id (ObjectId.) :title "OCaml" :tags ["functional" "static" "dsls"] }
doc7 { :_id (ObjectId.) :title "Haskell" :tags ["functional" "static" "dsls" "concurrency features"] }
- (mgcol/insert-batch coll [doc1 doc2 doc3 doc4 doc5 doc6 doc7])
result1 (with-collection coll
(find {})
(paginate :page 1 :per-page 3)
(sort { :title 1 })
(read-preference ReadPreference/PRIMARY)
(options com.mongodb.Bytes/QUERYOPTION_NOTIMEOUT))
result2 (with-collection coll
(find {})
(paginate :page 2 :per-page 3)
(sort { :title 1 }))
result3 (with-collection coll
(find {})
(paginate :page 3 :per-page 3)
(sort { :title 1 }))
result4 (with-collection coll
(find {})
(paginate :page 10 :per-page 3)
(sort { :title 1 }))]
(is (= [doc1 doc5 doc7] result1))
(is (= [doc2 doc6 doc4] result2))
(is (= [doc3] result3))
(is (empty? result4))))
(deftest combined-querying-dsl-example1
(let [coll "docs"
ma-doc { :_id (ObjectId.) :name "Massachusetts" :iso "MA" :population 6547629 :joined_in 1788 :capital "Boston" }
de-doc { :_id (ObjectId.) :name "Delaware" :iso "DE" :population 897934 :joined_in 1787 :capital "Dover" }
ny-doc { :_id (ObjectId.) :name "New York" :iso "NY" :population 19378102 :joined_in 1788 :capital "Albany" }
ca-doc { :_id (ObjectId.) :name "California" :iso "CA" :population 37253956 :joined_in 1850 :capital "Sacramento" }
tx-doc { :_id (ObjectId.) :name "Texas" :iso "TX" :population 25145561 :joined_in 1845 :capital "Austin" }
top3 (partial-query (limit 3))
by-population-desc (partial-query (sort { :population -1 }))
_ (mgcol/insert-batch coll [ma-doc de-doc ny-doc ca-doc tx-doc])
result (with-collection coll
(find {})
(merge top3)
(merge by-population-desc))]
(is (= result [ca-doc tx-doc ny-doc]))))
(deftest combined-querying-dsl-example2
(let [coll "docs"
ma-doc { :_id (ObjectId.) :name "Massachusetts" :iso "MA" :population 6547629 :joined_in 1788 :capital "Boston" }
de-doc { :_id (ObjectId.) :name "Delaware" :iso "DE" :population 897934 :joined_in 1787 :capital "Dover" }
ny-doc { :_id (ObjectId.) :name "New York" :iso "NY" :population 19378102 :joined_in 1788 :capital "Albany" }
ca-doc { :_id (ObjectId.) :name "California" :iso "CA" :population 37253956 :joined_in 1850 :capital "Sacramento" }
tx-doc { :_id (ObjectId.) :name "Texas" :iso "TX" :population 25145561 :joined_in 1845 :capital "Austin" }
top3 (partial-query (limit 3))
by-population-desc (partial-query (sort { :population -1 }))
_ (mgcol/insert-batch coll [ma-doc de-doc ny-doc ca-doc tx-doc])
result (with-collection coll
(find {})
(merge top3)
(merge by-population-desc)
(keywordize-fields false))]
;; documents have fields as strings,
;; not keywords
(is (= (map #(% "name") result)
(map #(% :name) [ca-doc tx-doc ny-doc])))))
(deftest combined-querying-dsl-example2
(let [coll "querying_docs"
ma-doc { :_id (ObjectId.) :name "Massachusetts" :iso "MA" :population 6547629 :joined_in 1788 :capital "Boston" }
de-doc { :_id (ObjectId.) :name "Delaware" :iso "DE" :population 897934 :joined_in 1787 :capital "Dover" }
ny-doc { :_id (ObjectId.) :name "New York" :iso "NY" :population 19378102 :joined_in 1788 :capital "Albany" }
ca-doc { :_id (ObjectId.) :name "California" :iso "CA" :population 37253956 :joined_in 1850 :capital "Sacramento" }
tx-doc { :_id (ObjectId.) :name "Texas" :iso "TX" :population 25145561 :joined_in 1845 :capital "Austin" }
top3 (partial-query (limit 3))
by-population-desc (partial-query (sort { :population -1 }))
_ (mc/insert-batch db coll [ma-doc de-doc ny-doc ca-doc tx-doc])
result (with-collection db coll
(find {})
(merge top3)
(merge by-population-desc)
(keywordize-fields false))]
;; documents have fields as strings,
;; not keywords
(is (= (map #(% "name") result)
(map #(% :name) [ca-doc tx-doc ny-doc]))))))

View file

@ -1,40 +1,55 @@
(set! *warn-on-reflection* true)
(ns monger.test.ragtime-test
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.test.helper :as helper]
monger.ragtime)
(:use clojure.test
[monger.test.fixtures :only [purge-migrations]]
ragtime.core))
monger.ragtime
[ragtime.protocols :refer :all]
[clojure.test :refer :all]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-collections
[f]
(mc/remove db "meta.migrations")
(f)
(mc/remove db "meta.migrations"))
(use-fixtures :each purge-migrations)
(use-fixtures :each purge-collections)
(when-not (get (System/getenv) "CI")
(deftest test-add-migration-id
(let [coll "meta.migrations"
key "1"]
(mc/remove db coll {})
(is (not (mc/any? db coll {:_id key})))
(is (not (some #{key} (applied-migration-ids db))))
(add-migration-id db key)
(is (mc/any? db coll {:_id key}))
(is (some #{key} (applied-migration-ids db)))))
(when-not (get (System/getenv) "CI")
(deftest test-add-migration-id
(let [db (mg/get-db "monger-test")
coll "meta.migrations"
key "1"]
(mc/remove db coll {})
(is (not (mc/any? db coll {:_id key})))
(is (not (contains? (applied-migration-ids db) key)))
(add-migration-id db key)
(is (mc/any? db coll {:_id key}))
(is (contains? (applied-migration-ids db) key))))
(deftest test-remove-migration-id
(let [coll "meta.migrations"
key "1"]
(mc/remove db coll {})
(add-migration-id db key)
(is (mc/any? db coll {:_id key}))
(is (some #{key} (applied-migration-ids db)))
(remove-migration-id db key)
(is (not (some #{key} (applied-migration-ids db))))))
(deftest test-remove-migration-id
(let [db (mg/get-db "monger-test")
coll "meta.migrations"
key "1"]
(mc/remove db coll {})
(add-migration-id db key)
(is (mc/any? db coll {:_id key}))
(is (contains? (applied-migration-ids db) key))
(remove-migration-id db key)
(is (not (contains? (applied-migration-ids db) key))))))
(deftest test-migrations-ordering
(let [coll "meta.migrations"
all-keys [ "9" "4" "7" "1" "5" "3" "6" "2" "8"]]
(mc/remove db coll {})
(doseq [key all-keys]
(add-migration-id db key))
(doseq [key all-keys]
(is (mc/any? db coll {:_id key}))
(is (some #{key} (applied-migration-ids db))))
(testing "Applied migrations must come out in creation order"
(is (= all-keys (applied-migration-ids db))))))))

View file

@ -1,276 +1,293 @@
(set! *warn-on-reflection* true)
(ns monger.test.regular-finders-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject]
org.bson.types.ObjectId
java.util.Date)
(:require [monger core util]
[monger.collection :as mgcol]
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.util :as mu]
[monger.result :as mgres]
[monger.conversion :as mgcnv]
[monger.test.helper :as helper])
(:use clojure.test
monger.operators
monger.test.fixtures))
[clojure.test :refer :all]
[monger.operators :refer :all]
[monger.conversion :refer [to-db-object]]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(use-fixtures :each (fn [f]
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "regular_finders_docs")
(mc/remove db "things")
(mc/remove db "libraries")
(f)
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "regular_finders_docs")
(mc/remove db "things")
(mc/remove db "libraries")))
(use-fixtures :each purge-people purge-docs purge-things purge-libraries)
;;
;; find-one
;;
(deftest find-one-full-document-when-collection-is-empty
(let [collection "regular_finders_docs"]
(is (nil? (mc/find-one db collection {})))))
(deftest find-one-full-document-as-map-when-collection-is-empty
(let [collection "regular_finders_docs"]
(mc/remove db collection)
(is (nil? (mc/find-one-as-map db collection {})))))
;;
;; find-one
;;
(deftest find-one-full-document-when-collection-has-matches
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mc/insert db collection doc)
found-one (mc/find-one db collection { :language "Clojure" })]
(is found-one)
(is (= (:_id doc) (mu/get-id found-one)))
(is (= (mgcnv/from-db-object found-one true) doc))
(is (= (mgcnv/to-db-object doc) found-one))))
(deftest find-one-full-document-when-collection-is-empty
(let [collection "docs"]
(is (nil? (mgcol/find-one collection {})))))
(deftest find-one-full-document-as-map-when-collection-is-empty
(let [collection "docs"]
(is (nil? (mgcol/find-one-as-map collection {})))))
(deftest find-one-full-document-when-collection-has-matches
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mgcol/insert collection doc)
found-one (mgcol/find-one collection { :language "Clojure" })]
(is (= (:_id doc) (monger.util/get-id found-one)))
(is (= (mgcnv/from-db-object found-one true) doc))
(is (= (mgcnv/to-db-object doc) found-one))))
(deftest find-one-full-document-as-map-when-collection-has-matches
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= doc (mgcol/find-one-as-map collection { :language "Clojure" })))))
(deftest find-one-full-document-as-map-when-collection-has-matches
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= doc (mc/find-one-as-map db collection { :language "Clojure" })))))
(deftest find-one-partial-document-when-collection-has-matches
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mgcol/insert collection doc)
loaded (mgcol/find-one collection { :language "Clojure" } [:language])]
(is (nil? (.get ^DBObject loaded "data-store")))
(is (= doc-id (monger.util/get-id loaded)))
(is (= "Clojure" (.get ^DBObject loaded "language")))))
(deftest find-one-partial-document-when-collection-has-matches
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mc/insert db collection doc)
loaded (mc/find-one db collection { :language "Clojure" } [:language])]
(is (nil? (.get ^DBObject loaded "data-store")))
(is (= doc-id (mu/get-id loaded)))
(is (= "Clojure" (.get ^DBObject loaded "language")))))
(deftest find-one-partial-document-using-field-negation-when-collection-has-matches
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mgcol/insert collection doc)
^DBObject loaded (mgcol/find-one collection { :language "Clojure" } {:data-store 0 :_id 0})]
(is (nil? (.get loaded "data-store")))
(is (nil? (.get loaded "_id")))
(is (nil? (monger.util/get-id loaded)))
(is (= "Clojure" (.get loaded "language")))))
(deftest find-one-partial-document-using-field-negation-when-collection-has-matches
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mc/insert db collection doc)
^DBObject loaded (mc/find-one db collection { :language "Clojure" } {:data-store 0 :_id 0})]
(is (nil? (.get loaded "data-store")))
(is (nil? (.get loaded "_id")))
(is (nil? (mu/get-id loaded)))
(is (= "Clojure" (.get loaded "language")))))
(deftest find-one-partial-document-as-map-when-collection-has-matches
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= { :data-store "MongoDB", :_id doc-id } (mgcol/find-one-as-map collection { :language "Clojure" } [:data-store])))))
(deftest find-one-partial-document-as-map-when-collection-has-matches
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= { :data-store "MongoDB", :_id doc-id }
(mc/find-one-as-map db collection { :language "Clojure" } [:data-store])))))
(deftest find-one-partial-document-as-map-when-collection-has-matches-with-keywordize
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
fields [:data-store]
_id (mgcol/insert collection doc)
loaded (mgcol/find-one-as-map collection { :language "Clojure" } fields true)
]
(is (= { :data-store "MongoDB", :_id doc-id } loaded ))))
(deftest find-one-partial-document-as-map-when-collection-has-matches-with-keywordize
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
fields [:data-store]
_id (mc/insert db collection doc)
loaded (mc/find-one-as-map db collection { :language "Clojure" } fields true)
]
(is (= { :data-store "MongoDB", :_id doc-id } loaded ))))
(deftest find-one-partial-document-as-map-when-collection-has-matches-with-keywordize-false
(let [collection "docs"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
fields [:data-store]
_id (mgcol/insert collection doc)
loaded (mgcol/find-one-as-map collection { :language "Clojure" } fields false)
]
(is (= { "_id" doc-id, "data-store" "MongoDB" } loaded ))))
(deftest find-one-partial-document-as-map-when-collection-has-matches-with-keywordize-false
(let [collection "regular_finders_docs"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
fields [:data-store]
_id (mc/insert db collection doc)
loaded (mc/find-one-as-map db collection { :language "Clojure" } fields false)]
(is (= { "_id" doc-id, "data-store" "MongoDB" } loaded ))))
;;
;; find-by-id
;;
;;
;; find-by-id
;;
(deftest find-full-document-by-string-id-when-that-document-does-not-exist
(let [collection "libraries"
doc-id (monger.util/random-uuid)]
(is (nil? (mgcol/find-by-id collection doc-id)))))
(deftest find-full-document-by-string-id-when-that-document-does-not-exist
(let [collection "libraries"
doc-id (mu/random-uuid)]
(is (nil? (mc/find-by-id db collection doc-id)))))
(deftest find-full-document-by-string-id-when-id-is-nil
(let [collection "libraries"
doc-id nil]
(is (thrown? IllegalArgumentException (mgcol/find-by-id collection doc-id)))))
(deftest find-full-document-by-string-id-when-id-is-nil
(let [collection "libraries"
doc-id nil]
(is (thrown? IllegalArgumentException (mc/find-by-id db collection doc-id)))))
(deftest find-full-document-by-object-id-when-that-document-does-not-exist
(let [collection "libraries"
doc-id (ObjectId.)]
(is (nil? (mgcol/find-by-id collection doc-id)))))
(deftest find-full-document-by-object-id-when-that-document-does-not-exist
(let [collection "libraries"
doc-id (ObjectId.)]
(is (nil? (mc/find-by-id db collection doc-id)))))
(deftest find-full-document-by-id-as-map-when-that-document-does-not-exist
(let [collection "libraries"
doc-id (monger.util/random-uuid)]
(is (nil? (mgcol/find-map-by-id collection doc-id)))))
(deftest find-full-document-by-id-as-map-when-that-document-does-not-exist
(let [collection "libraries"
doc-id (mu/random-uuid)]
(is (nil? (mc/find-map-by-id db collection doc-id)))))
(deftest find-full-document-by-id-as-map-when-id-is-nil
(let [collection "libraries"
doc-id nil]
(is (thrown? IllegalArgumentException
(mgcol/find-map-by-id collection doc-id)))))
(deftest find-full-document-by-id-as-map-when-id-is-nil
(let [collection "libraries"
doc-id nil]
(is (thrown? IllegalArgumentException
(mc/find-map-by-id db collection doc-id)))))
(deftest find-full-document-by-string-id-when-document-does-exist
(let [collection "libraries"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= (doc (mgcol/find-by-id collection doc-id))))))
(deftest find-full-document-by-string-id-when-document-does-exist
(let [collection "libraries"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= (to-db-object doc) (mc/find-by-id db collection doc-id)))))
(deftest find-full-document-by-object-id-when-document-does-exist
(let [collection "libraries"
doc-id (ObjectId.)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= (doc (mgcol/find-by-id collection doc-id))))))
(deftest find-full-document-by-object-id-when-document-does-exist
(let [collection "libraries"
doc-id (ObjectId.)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= (to-db-object doc) (mc/find-by-id db collection doc-id)))))
(deftest find-full-document-map-by-string-id-when-document-does-exist
(let [collection "libraries"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= (doc (mgcol/find-map-by-id collection doc-id))))))
(deftest find-full-document-map-by-string-id-when-document-does-exist
(let [collection "libraries"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= doc (mc/find-map-by-id db collection doc-id)))))
(deftest find-full-document-map-by-object-id-when-document-does-exist
(let [collection "libraries"
doc-id (ObjectId.)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= (doc (mgcol/find-map-by-id collection doc-id))))))
(deftest find-full-document-map-by-object-id-when-document-does-exist
(let [collection "libraries"
doc-id (ObjectId.)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= doc (mc/find-map-by-id db collection doc-id)))))
(deftest find-partial-document-by-id-when-document-does-exist
(let [collection "libraries"
doc-id (monger.util/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mgcol/insert collection doc)
(is (= ({ :language "Clojure" } (mgcol/find-by-id collection doc-id [ :language ]))))))
(deftest find-partial-document-by-id-when-document-does-exist
(let [collection "libraries"
doc-id (mu/random-uuid)
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }]
(mc/insert db collection doc)
(is (= (to-db-object { :_id doc-id :language "Clojure" })
(mc/find-by-id db collection doc-id [ :language ])))))
(deftest find-partial-document-as-map-by-id-when-document-does-exist
(let [collection "libraries"
doc-id (monger.util/random-uuid)
fields [:data-store]
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mgcol/insert collection doc)
loaded (mgcol/find-map-by-id collection doc-id [ :language ])]
(is (= { :language "Clojure", :_id doc-id } loaded ))
)
)
(deftest find-partial-document-as-map-by-id-when-document-does-exist
(let [collection "libraries"
doc-id (mu/random-uuid)
fields [:data-store]
doc { :data-store "MongoDB", :language "Clojure", :_id doc-id }
_ (mc/insert db collection doc)
loaded (mc/find-map-by-id db collection doc-id [ :language ])]
(is (= { :language "Clojure", :_id doc-id } loaded ))))
;;
;; find
;;
;;
;; find
;;
(deftest find-full-document-when-collection-is-empty
(let [collection "docs"
cursor (mgcol/find collection)]
(is (empty? (iterator-seq cursor)))))
(deftest find-full-document-when-collection-is-empty
(let [collection "regular_finders_docs"
cursor (mc/find db collection)]
(is (empty? (iterator-seq cursor)))))
(deftest find-document-seq-when-collection-is-empty
(let [collection "docs"]
(is (empty? (mgcol/find-seq collection)))))
(deftest find-document-seq-when-collection-is-empty
(let [collection "regular_finders_docs"]
(is (empty? (mc/find-seq db collection)))))
(deftest find-multiple-documents-when-collection-is-empty
(let [collection "libraries"]
(is (empty? (mgcol/find collection { :language "Scala" })))))
(deftest find-multiple-documents-when-collection-is-empty
(let [collection "libraries"]
(is (empty? (mc/find db collection { :language "Scala" })))))
(deftest find-multiple-maps-when-collection-is-empty
(let [collection "libraries"]
(is (empty? (mgcol/find-maps collection { :language "Scala" })))))
(deftest find-multiple-maps-when-collection-is-empty
(let [collection "libraries"]
(is (empty? (mc/find-maps db collection { :language "Scala" })))))
(deftest find-multiple-documents-by-regex
(let [collection "libraries"]
(mgcol/insert-batch collection [{ :language "Clojure", :name "monger" }
{ :language "Java", :name "nhibernate" }
{ :language "JavaScript", :name "sprout-core" }])
(is (= 2 (monger.core/count (mgcol/find collection { :language #"Java*" }))))))
(deftest find-multiple-documents-by-regex
(let [collection "libraries"]
(mc/insert-batch db collection [{ :language "Clojure", :name "monger" }
{ :language "Java", :name "nhibernate" }
{ :language "JavaScript", :name "sprout-core" }])
(is (= 2 (monger.core/count (mc/find db collection { :language #"Java*" }))))))
(deftest find-multiple-documents
(let [collection "libraries"]
(mgcol/insert-batch collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(is (= 1 (monger.core/count (mgcol/find collection { :language "Scala" }))))
(is (= 3 (.count (mgcol/find collection { :language "Clojure" }))))
(is (empty? (mgcol/find collection { :language "Java" })))))
(deftest find-multiple-documents
(let [collection "libraries"]
(mc/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 (mc/find db collection { :language "Scala" }))))
(is (= 3 (.count (mc/find db collection { :language "Clojure" }))))
(is (empty? (mc/find db collection { :language "Java" })))))
(deftest find-document-specify-fields
(let [collection "libraries"
_ (mgcol/insert collection { :language "Clojure", :name "monger" })
result (mgcol/find collection { :language "Clojure"} [:language])]
(is (= (seq [:_id :language]) (keys (mgcnv/from-db-object (.next result) true))))))
(deftest find-document-specify-fields
(let [collection "libraries"
_ (mc/insert db collection { :language "Clojure", :name "monger" })
result (mc/find db collection { :language "Clojure"} [:language])]
(is (= (set [:_id :language]) (-> (mgcnv/from-db-object (.next result) true) keys set)))))
(deftest find-and-iterate-over-multiple-documents-the-hard-way
(let [collection "libraries"]
(mgcol/insert-batch 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 collection { :language "Clojure" })))]
(is (= "Clojure" (:language doc))))))
(deftest find-and-iterate-over-multiple-documents-the-hard-way
(let [collection "libraries"]
(mc/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))
(mc/find-seq db collection { :language "Clojure" })))]
(is (= "Clojure" (:language doc))))))
(deftest find-and-iterate-over-multiple-documents
(let [collection "libraries"]
(mgcol/insert-batch collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(doseq [doc (take 3 (mgcol/find-maps collection { :language "Clojure" }))]
(is (= "Clojure" (:language doc))))))
(deftest find-and-iterate-over-multiple-documents
(let [collection "libraries"]
(mc/insert-batch db collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(doseq [doc (take 3 (mc/find-maps db collection { :language "Clojure" }))]
(is (= "Clojure" (:language doc))))))
(deftest find-multiple-maps
(let [collection "libraries"]
(mgcol/insert-batch collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(is (= 1 (clojure.core/count (mgcol/find-maps collection { :language "Scala" }))))
(is (= 3 (.count (mgcol/find-maps collection { :language "Clojure" }))))
(is (empty? (mgcol/find-maps collection { :language "Java" })))
(is (empty? (mgcol/find-maps monger.core/*mongodb-database* collection { :language "Java" } [:language :name])))))
(deftest find-multiple-maps
(let [collection "libraries"]
(mc/insert-batch db collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(is (= 1 (clojure.core/count (mc/find-maps db collection { :language "Scala" }))))
(is (= 3 (.count (mc/find-maps db collection { :language "Clojure" }))))
(is (empty? (mc/find-maps db collection { :language "Java" })))
(is (empty? (mc/find-maps db collection { :language "Java" } [:language :name])))))
(deftest find-multiple-partial-documents
(let [collection "libraries"]
(mgcol/insert-batch collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(let [scala-libs (mgcol/find collection { :language "Scala" } [:name])
clojure-libs (mgcol/find 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 collection { :language "Erlang" } [:name]))))))
(deftest find-multiple-partial-documents
(let [collection "libraries"]
(mc/insert-batch db collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :language "Scala", :name "akka" }])
(let [scala-libs (mc/find db collection { :language "Scala" } [:name])
clojure-libs (mc/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? (mc/find db collection { :language "Erlang" } [:name]))))))
(deftest find-maps-with-keywordize-false
(let [collection "libraries"]
(mc/insert-batch db collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }])
(let [results (mc/find-maps db collection {:name "langohr"} [] false)]
(is (= 1 (.count results)))
(is (= (get (first results) "language") "Clojure"))))))

View file

@ -1,54 +1,25 @@
(ns monger.test.result-test
(:import [com.mongodb BasicDBObject WriteResult WriteConcern] java.util.Date)
(:require [monger core collection conversion]
[monger.test.helper :as helper])
(:use clojure.test))
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.result :as mgres]
monger.util
[clojure.test :refer :all]))
(helper/connect!)
;;
;; MongoCommandResult
;;
(deftest test-ok?
(let [result-that-is-not-ok-1 (doto (BasicDBObject.) (.put "ok" 0))
result-that-is-not-ok-2 (doto (BasicDBObject.) (.put "ok" "false"))
result-that-is-ok-1 (doto (BasicDBObject.) (.put "ok" 1))
result-that-is-ok-2 (doto (BasicDBObject.) (.put "ok" "true"))
result-that-is-ok-3 (doto (BasicDBObject.) (.put "ok" 1.0))]
(is (not (monger.result/ok? result-that-is-not-ok-1)))
(is (not (monger.result/ok? result-that-is-not-ok-2)))
(is (monger.result/ok? result-that-is-ok-1))
(is (monger.result/ok? result-that-is-ok-2))
(is (monger.result/ok? result-that-is-ok-3))))
(deftest test-has-error?
(let [result-that-has-no-error1 (doto (BasicDBObject.) (.put "ok" 0))
result-that-has-no-error2 (doto (BasicDBObject.) (.put "err" ""))
result-that-has-error1 (doto (BasicDBObject.) (.put "err" (BasicDBObject.)))]
(is (not (monger.result/has-error? result-that-has-no-error1)))
(is (not (monger.result/has-error? result-that-has-no-error2)))
(is (monger.result/has-error? result-that-has-error1))))
(deftest test-updated-existing?-with-db-object
(let [input1 (doto (BasicDBObject.) (.put "updatedExisting" true))
input2 (doto (BasicDBObject.) (.put "updatedExisting" false))
input3 (BasicDBObject.)]
(is (monger.result/updated-existing? input1))
(is (not (monger.result/updated-existing? input2)))
(is (not (monger.result/updated-existing? input3)))))
(deftest test-updated-existing?-with-write-result
(monger.collection/remove "libraries")
(let [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 (monger.result/updated-existing? (monger.collection/update collection { :language "Clojure" } doc :upsert true))))
(is (monger.result/updated-existing? (monger.collection/update collection { :language "Clojure" } doc :upsert true)))
(monger.result/updated-existing? (monger.collection/update collection { :language "Clojure" } modified-doc :multi false :upsert true))
(monger.collection/remove collection)))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(deftest test-updated-existing?-with-write-result
(mc/remove db "libraries")
(let [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 }]
(let [result (mc/update db collection { :language "Clojure" } doc {:upsert true})]
(is (not (mgres/updated-existing? result)))
(is (= 1 (mgres/affected-count result))))
(is (mgres/updated-existing? (mc/update db collection { :language "Clojure" } doc {:upsert true})))
(is (mgres/updated-existing? (mc/update db collection { :language "Clojure" } modified-doc {:multi false :upsert true})))
(is (= 1 (mgres/affected-count (mc/remove db collection { :_id doc-id }))))
(mc/remove db collection)
(mg/disconnect conn))))

View file

@ -1,54 +1,50 @@
(ns monger.test.ring.clojure-session-store-test
(:require [monger core util]
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.test.helper :as helper])
(:use clojure.test
ring.middleware.session.store
monger.ring.session-store))
[clojure.test :refer :all]
[ring.middleware.session.store :refer :all]
[monger.ring.session-store :refer :all]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-sessions
[f]
(mc/remove db "sessions")
(f)
(mc/remove db "sessions"))
(defn purge-sessions
[f]
(mc/remove "web_sessions")
(mc/remove "sessions")
(f)
(mc/remove "web_sessions")
(mc/remove "sessions"))
(use-fixtures :each purge-sessions)
(use-fixtures :each purge-sessions)
(deftest test-reading-a-session-that-does-not-exist
(let [store (session-store)]
(is (= {} (read-session store "a-missing-key-1228277")))))
(deftest test-reading-a-session-that-does-not-exist
(let [store (session-store db "sessions")]
(is (= {} (read-session store "a-missing-key-1228277")))))
(deftest test-reading-a-session-that-does-exist
(let [store (session-store)
sk (write-session store nil {:library "Monger"})
m (read-session store sk)]
(is sk)
(is (and (:_id m)))
(is (= (dissoc m :_id)
{:library "Monger"}))))
(deftest test-reading-a-session-that-does-exist
(let [store (session-store db "sessions")
sk (write-session store nil {:library "Monger"})
m (read-session store sk)]
(is sk)
(is (and (:_id m)))
(is (= (dissoc m :_id)
{:library "Monger"}))))
(deftest test-updating-a-session
(let [store (session-store "sessions")
sk1 (write-session store nil {:library "Monger"})
sk2 (write-session store sk1 {:library "Ring"})
m (read-session store sk2)]
(is (and sk1 sk2))
(is (and (:_id m)))
(is (= sk1 sk2))
(is (= (dissoc m :_id)
{:library "Ring"}))))
(deftest test-updating-a-session
(let [store (session-store db "sessions")
sk1 (write-session store nil {:library "Monger"})
sk2 (write-session store sk1 {:library "Ring"})
m (read-session store sk2)]
(is (and sk1 sk2))
(is (and (:_id m)))
(is (= sk1 sk2))
(is (= (dissoc m :_id)
{:library "Ring"}))))
(deftest test-deleting-a-session
(let [store (session-store "sessions")
sk (write-session store nil {:library "Monger"})]
(is (nil? (delete-session store sk)))
(is (= {} (read-session store sk)))))
(deftest test-deleting-a-session
(let [store (session-store db "sessions")
sk (write-session store nil {:library "Monger"})]
(is (nil? (delete-session store sk)))
(is (= {} (read-session store sk))))))

View file

@ -1,62 +1,54 @@
(ns monger.test.ring.session-store-test
(:require [monger core util]
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.test.helper :as helper])
(:use clojure.test
ring.middleware.session.store
monger.ring.session-store))
[clojure.test :refer :all]
[ring.middleware.session.store :refer :all]
[monger.ring.session-store :refer :all]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-sessions
[f]
(mc/remove db "sessions")
(f)
(mc/remove db "sessions"))
(defn purge-sessions
[f]
(mc/remove "web_sessions")
(mc/remove "sessions")
(f)
(mc/remove "web_sessions")
(mc/remove "sessions"))
(use-fixtures :each purge-sessions)
(use-fixtures :each purge-sessions)
(deftest test-reading-a-session-that-does-not-exist
(let [store (monger-store db "sessions")]
(is (= {} (read-session store "a-missing-key-1228277")))))
(deftest test-reading-a-session-that-does-exist
(let [store (monger-store db "sessions")
sk (write-session store nil {:library "Monger"})
m (read-session store sk)]
(is sk)
(is (and (:_id m) (:date m)))
(is (= (dissoc m :_id :date)
{:library "Monger"}))))
(deftest test-reading-a-session-that-does-not-exist
(let [store (monger-store)]
(is (= {} (read-session store "a-missing-key-1228277")))))
(deftest test-updating-a-session
(let [store (monger-store db "sessions")
sk1 (write-session store nil {:library "Monger"})
sk2 (write-session store sk1 {:library "Ring"})
m (read-session store sk2)]
(is (and sk1 sk2))
(is (and (:_id m) (:date m)))
(is (= sk1 sk2))
(is (= (dissoc m :_id :date)
{:library "Ring"}))))
(deftest test-deleting-a-session
(let [store (monger-store db "sessions")
sk (write-session store nil {:library "Monger"})]
(is (nil? (delete-session store sk)))
(is (= {} (read-session store sk)))))
(deftest test-reading-a-session-that-does-exist
(let [store (monger-store)
sk (write-session store nil {:library "Monger"})
m (read-session store sk)]
(is sk)
(is (and (:_id m) (:date m)))
(is (= (dissoc m :_id :date)
{:library "Monger"}))))
(deftest test-updating-a-session
(let [store (monger-store "sessions")
sk1 (write-session store nil {:library "Monger"})
sk2 (write-session store sk1 {:library "Ring"})
m (read-session store sk2)]
(is (and sk1 sk2))
(is (and (:_id m) (:date m)))
(is (= sk1 sk2))
(is (= (dissoc m :_id :date)
{:library "Ring"}))))
(deftest test-deleting-a-session
(let [store (monger-store "sessions")
sk (write-session store nil {:library "Monger"})]
(is (nil? (delete-session store sk)))
(is (= {} (read-session store sk)))))
(deftest test-reader-extensions
(let [d (java.util.Date.)
oid (org.bson.types.ObjectId.)]
(binding [*print-dup* true]
(pr-str d)
(pr-str oid))))
(deftest test-reader-extensions
(let [d (java.util.Date.)
oid (org.bson.types.ObjectId.)]
(binding [*print-dup* true]
(pr-str d)
(pr-str oid)))))

View file

@ -1,42 +1,40 @@
(ns monger.test.stress-test
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor]
java.util.Date)
(:require monger.core
[monger.test.helper :as helper])
(:use clojure.test))
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.conversion :refer [to-db-object from-db-object]]
[clojure.test :refer :all])
(:import [com.mongodb WriteConcern]
java.util.Date))
;;
;; Fixture functions
;;
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-collection
[coll f]
(mc/remove db coll)
(f)
(mc/remove db coll))
(defn purge-collection
[collection-name, f]
(monger.collection/remove collection-name)
(f)
(monger.collection/remove collection-name))
(defn purge-things-collection
[f]
(purge-collection "things" f))
(defn purge-things-collection
[f]
(purge-collection "things" f))
(use-fixtures :each purge-things-collection)
(use-fixtures :each purge-things-collection)
(deftest ^{:performance true} insert-large-batches-of-documents-without-object-ids
(doseq [n [10 100 1000 10000 20000]]
(let [collection "things"
docs (map (fn [i]
(to-db-object { :title "Untitled" :created-at (Date.) :number i }))
(take n (iterate inc 1)))]
(mc/remove db collection)
(println "Inserting " n " documents...")
(time (mc/insert-batch db collection docs))
(is (= n (mc/count db collection))))))
;;
;; Tests
;;
(monger.core/set-default-write-concern! WriteConcern/NORMAL)
(deftest ^{:performance true} insert-large-batches-of-documents-without-object-ids
(doseq [n [1000 10000 100000]]
(let [collection "things"
docs (map (fn [i]
(monger.conversion/to-db-object { :title "Untitled" :created-at (Date.) :number i }))
(take n (iterate inc 1)))]
(monger.collection/remove collection)
(println "Inserting " n " documents...")
(time (monger.collection/insert-batch collection docs))
(is (= n (monger.collection/count collection))))))
(deftest ^{:performance true} convert-large-number-of-dbojects-to-maps
(doseq [n [10 100 1000 20000 40000]]
(let [docs (map (fn [i]
(to-db-object {:title "Untitled" :created-at (Date.) :number i}))
(take n (iterate inc 1)))]
(time (doall (map (fn [x] (from-db-object x true)) docs)))))))

View file

@ -1,151 +1,169 @@
(set! *warn-on-reflection* true)
(ns monger.test.updating-test
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject]
(:import [com.mongodb WriteResult WriteConcern DBObject]
org.bson.types.ObjectId
java.util.Date)
(:require [monger core util]
(:require [monger.core :as mg]
[monger.collection :as mc]
[monger.util :as mu]
[monger.result :as mr]
[monger.test.helper :as helper])
(:use clojure.test
monger.operators
monger.test.fixtures
[monger.conversion :only [to-db-object]]))
[clojure.test :refer :all]
[monger.operators :refer :all]
[monger.conversion :refer [to-db-object]]))
(helper/connect!)
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(defn purge-collections
[f]
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "libraries")
(f)
(mc/remove db "people")
(mc/remove db "docs")
(mc/remove db "things")
(mc/remove db "libraries"))
(use-fixtures :each purge-people purge-docs purge-things purge-libraries)
(use-fixtures :each purge-collections)
(deftest ^{:updating true} update-document-by-id-without-upsert
(let [collection "libraries"
doc-id (mu/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 (= (to-db-object doc) (mc/find-by-id db collection doc-id)))
(mc/update db collection { :_id doc-id } { $set { :language "Erlang" } })
(is (= (to-db-object modified-doc) (mc/find-by-id db collection doc-id)))))
(deftest ^{:updating true} update-document-by-id-without-upsert-using-update-by-id
(let [collection "libraries"
doc-id (mu/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 (= (to-db-object doc) (mc/find-by-id db collection doc-id)))
(mc/update-by-id db collection doc-id { $set { :language "Erlang" } })
(is (= (to-db-object modified-doc) (mc/find-by-id db collection doc-id)))))
(deftest ^{:updating true} update-nested-document-fields-without-upsert-using-update-by-id
(let [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 (= (to-db-object doc) (mc/find-by-id db collection doc-id)))
(mc/update-by-id db collection doc-id { $set { "language.primary" "Erlang" }})
(is (= (to-db-object modified-doc) (mc/find-by-id db collection doc-id)))))
;;
;; update, save
;;
(deftest ^{:updating true} update-document-by-id-without-upsert
(let [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 collection doc)
(is (= (doc (mc/find-by-id collection doc-id))))
(mc/update collection { :_id doc-id } { :language "Erlang" })
(is (= (modified-doc (mc/find-by-id collection doc-id))))))
(deftest ^{:updating true} update-document-by-id-without-upsert-using-update-by-id
(let [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 collection doc)
(is (= (doc (mc/find-by-id collection doc-id))))
(mc/update-by-id collection doc-id { :language "Erlang" })
(is (= (modified-doc (mc/find-by-id collection doc-id))))))
(deftest ^{:updating true} update-nested-document-fields-without-upsert-using-update-by-id
(let [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 collection doc)
(is (= (doc (mc/find-by-id collection doc-id))))
(mc/update-by-id collection doc-id { $set { "language.primary" "Erlang" }})
(is (= (modified-doc (mc/find-by-id collection doc-id))))))
(deftest ^{:updating true} update-multiple-documents
(let [collection "libraries"]
(mc/insert-batch db collection [{ :language "Clojure", :name "monger" }
{ :language "Clojure", :name "langohr" }
{ :language "Clojure", :name "incanter" }
{ :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} update-multiple-documents
(let [collection "libraries"]
(mc/insert collection { :language "Clojure", :name "monger" })
(mc/insert collection { :language "Clojure", :name "langohr" })
(mc/insert collection { :language "Clojure", :name "incanter" })
(mc/insert collection { :language "Scala", :name "akka" })
(is (= 3 (mc/count collection { :language "Clojure" })))
(is (= 1 (mc/count collection { :language "Scala" })))
(is (= 0 (mc/count collection { :language "Python" })))
(mc/update collection { :language "Clojure" } { $set { :language "Python" } } :multi true)
(is (= 0 (mc/count collection { :language "Clojure" })))
(is (= 1 (mc/count collection { :language "Scala" })))
(is (= 3 (mc/count collection { :language "Python" })))))
(deftest ^{:updating true} save-a-new-document
(let [collection "people"
document {:name "Joe" :age 30}]
(is (mc/save db "people" document))
(is (= 1 (mc/count db collection)))))
(deftest ^{:updating true} save-and-return-a-new-document
(let [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-document
(let [collection "people"
document {:name "Joe" :age 30}]
(is (monger.result/ok? (mc/save "people" document)))
(is (= 1 (mc/count collection)))))
(deftest ^{:updating true} save-and-return-a-new-document
(let [collection "people"
document {:name "Joe" :age 30}
returned (mc/save-and-return "people" document)]
(is (:_id returned))
(is (= document (dissoc returned :_id)))
(is (= 1 (mc/count collection)))))
(deftest ^{:updating true} save-a-new-basic-db-object
(let [collection "people"
doc (to-db-object {:name "Joe" :age 30})]
(is (nil? (monger.util/get-id doc)))
(mc/save monger.core/*mongodb-database* "people" doc WriteConcern/SAFE)
(is (not (nil? (monger.util/get-id doc))))))
(deftest ^{:updating true} save-a-new-basic-db-object
(let [collection "people"
doc (to-db-object {:name "Joe" :age 30})]
(is (nil? (mu/get-id doc)))
(mc/save db "people" doc WriteConcern/SAFE)
(is (not (nil? (mu/get-id doc))))))
(deftest ^{:updating true} update-an-existing-document-using-save
(let [collection "people"
doc-id "people-1"
document { :_id doc-id, :name "Joe", :age 30 }]
(is (monger.result/ok? (mc/insert "people" document)))
(is (= 1 (mc/count collection)))
(mc/save collection { :_id doc-id, :name "Alan", :age 40 })
(is (= 1 (mc/count collection { :name "Alan", :age 40 })))))
(deftest ^{:updating true} update-an-existing-document-using-save
(let [collection "people"
doc-id "people-1"
document { :_id doc-id, :name "Joe", :age 30 }]
(is (mc/insert db collection 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 [collection "people"
document (mc/insert-and-return "people" {:name "Joe" :age 30})
doc-id (:_id document)
updated (mc/save-and-return collection {:_id doc-id :name "Alan" :age 40})]
(is (= {:_id doc-id :name "Alan" :age 40} updated))
(is (= 1 (mc/count collection)))
(is (= 1 (mc/count collection {:name "Alan" :age 40})))))
(deftest ^{:updating true} update-an-existing-document-using-save-and-return
(let [collection "people"
document (mc/insert-and-return db collection {: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 [collection "people"
doc-id (monger.util/object-id)
document { :_id doc-id, :name "Joe", :age 30 }]
(is (monger.result/ok? (mc/insert "people" document)))
(is (= 1 (mc/count collection)))
(is (= 0 (mc/count collection { :has_kids true })))
(mc/update collection { :_id doc-id } { $set { :has_kids true } })
(is (= 1 (mc/count collection { :has_kids true })))))
(deftest ^{:updating true} set-an-attribute-on-existing-document-using-update
(let [collection "people"
doc-id (mu/object-id)
document { :_id doc-id, :name "Joe", :age 30 }]
(is (mc/insert db collection 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 [collection "matches"
doc-id (monger.util/object-id)
document { :_id doc-id :abc 0 :def 10 }]
(mc/remove collection)
(is (monger.result/ok? (mc/insert collection document)))
(is (= 1 (mc/count collection {:abc {$exists true} :def {$exists true}})))
(mc/update collection {:abc {$exists true} :def {$exists true}} {$inc {:abc 1 :def 0}})
(is (= 1 (mc/count collection { :abc 1 })))))
(deftest ^{:updating true} increment-multiple-fields-using-exists-operator-and-update
(let [collection "matches"
doc-id (mu/object-id)
document { :_id doc-id :abc 0 :def 10 }]
(mc/remove db collection)
(is (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
(let [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 (monger.result/updated-existing? (mc/update collection { :language "Clojure" } doc :upsert true))))
(is (= 1 (mc/count collection)))
(is (monger.result/updated-existing? (mc/update collection { :language "Clojure" } modified-doc :multi false :upsert true)))
(is (= 1 (mc/count collection)))
(is (= (modified-doc (mc/find-by-id collection doc-id))))
(mc/remove collection)))
(deftest ^{:updating true} upsert-a-document-using-update
(let [collection "libraries"
doc-id (mu/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 (= (to-db-object modified-doc) (mc/find-by-id db collection doc-id)))
(mc/remove db collection)))
(deftest ^{:updating true} upsert-a-document-using-upsert
(let [collection "libraries"
doc-id (mu/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 (= (to-db-object modified-doc) (mc/find-by-id db collection doc-id)))
(mc/remove db collection))))

View file

@ -1,7 +1,7 @@
(ns monger.test.util-test
(:import com.mongodb.DBObject)
(:require [monger util conversion])
(:use clojure.test))
(:require [monger util conversion]
[clojure.test :refer :all]))
(deftest get-object-id

View file

@ -0,0 +1,11 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.mongodb" level="WARN"/>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>