jor 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/Gemfile +2 -0
- data/LICENCE +22 -0
- data/README.md +319 -0
- data/Rakefile +10 -0
- data/config.ru +2 -0
- data/jor.gemspec +29 -0
- data/lib/jor.rb +14 -0
- data/lib/jor/collection.rb +449 -0
- data/lib/jor/doc.rb +62 -0
- data/lib/jor/errors.rb +96 -0
- data/lib/jor/server.rb +52 -0
- data/lib/jor/storage.rb +88 -0
- data/lib/jor/version.rb +3 -0
- data/test/test_helper.rb +11 -0
- data/test/test_helpers/fixtures.rb +71 -0
- data/test/unit/collection_test.rb +884 -0
- data/test/unit/doc_test.rb +139 -0
- data/test/unit/server_test.rb +113 -0
- data/test/unit/storage_test.rb +171 -0
- data/test/unit/test_case.rb +21 -0
- metadata +170 -0
data/lib/jor/doc.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
module JOR
|
3
|
+
class Doc
|
4
|
+
|
5
|
+
def self.paths(path,h)
|
6
|
+
if h.class==Hash
|
7
|
+
v = []
|
8
|
+
h.each do |k,val|
|
9
|
+
if JOR::Storage::SELECTORS_ALL.member?(k)
|
10
|
+
return [{"path_to" => path, "obj" => h, "class" => h.class, "selector" => true}]
|
11
|
+
else
|
12
|
+
raise InvalidFieldName.new(k) if ((k!="_id") && (k!="_created_at") && (k!="_updated_at")) && (k[0]=="_" || k[0]=="$")
|
13
|
+
v << paths("#{path}/#{k}",val)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return v.flatten
|
17
|
+
else
|
18
|
+
if h.class==Array
|
19
|
+
v = []
|
20
|
+
if h.size>0
|
21
|
+
h.each do |item|
|
22
|
+
v << paths("#{path}",item)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
v << ["#{path}"]
|
26
|
+
end
|
27
|
+
return v.flatten
|
28
|
+
else
|
29
|
+
return [{"path_to" => path, "obj" => h, "class" => h.class}]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.difference(set, set_to_substract)
|
35
|
+
return set if set_to_substract.nil? || set_to_substract.size==0
|
36
|
+
|
37
|
+
to_exclude = []
|
38
|
+
set_to_substract.each do |item|
|
39
|
+
raise FieldIdCannotBeExcludedFromIndex.new unless item["path_to"].match(/\/_id/)==nil
|
40
|
+
to_exclude << Regexp.new("^#{item["path_to"]}")
|
41
|
+
end
|
42
|
+
|
43
|
+
res = []
|
44
|
+
set.each do |item|
|
45
|
+
not_found = true
|
46
|
+
to_exclude.each do |re|
|
47
|
+
not_found = not_found && re.match(item["path_to"])==nil
|
48
|
+
end
|
49
|
+
res << item if not_found
|
50
|
+
end
|
51
|
+
return res
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.deep_merge(dest, source)
|
55
|
+
res = Hash.new
|
56
|
+
dest.merge(source) do |key, old_v, new_v|
|
57
|
+
res[key] = ((old_v.class == Hash) && (new_v.class == Hash)) ? deep_merge(old_v, new_v) : new_v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/jor/errors.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
module JOR
|
3
|
+
class Error < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class NoResults < Error
|
7
|
+
def initialize(doc)
|
8
|
+
super %(no results found for "#{doc}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TypeNotSupported < Error
|
13
|
+
def initialize(class_name)
|
14
|
+
super %(Type #{class_name} not supported)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class InvalidFieldName < Error
|
19
|
+
def initialize(field)
|
20
|
+
super %(Invalid character in field name "#{field}". Cannot start with '_' or '$')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class InvalidDocumentId < Error
|
25
|
+
def initialize(id)
|
26
|
+
super %(The document "_id" must be a positive integer (>=0), #{id} is not valid)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class DocumentIdAlreadyExists < Error
|
31
|
+
def initialize(id, name)
|
32
|
+
super %(A document with _id #{id} already exists in collection "{name}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class DocumentNeedsId < Error
|
37
|
+
def initialize(name)
|
38
|
+
super %(The collection #{name} is not auto-incremental. You must define the "_id" of the document")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class DocumentDoesNotNeedId < Error
|
43
|
+
def initialize(name)
|
44
|
+
super %(The collection #{name} is auto-incremental. You must not define the "_id" of the document")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class IncompatibleSelectors < Error
|
49
|
+
def initialize(str)
|
50
|
+
super %(Incompatible selectors in "#{str}". They must be grouped like this #{Storage::SELECTORS})
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class NotInCollection < Error
|
55
|
+
def initialize
|
56
|
+
super %(The current collection is undefined)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class CollectionDoesNotExist < Error
|
61
|
+
def initialize(str)
|
62
|
+
super %(Collection "#{str}" does not exist)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class CollectionAlreadyExists < Error
|
67
|
+
def initialize(str)
|
68
|
+
super %(Collection "#{str}" already exists)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class CollectionNotValid < Error
|
73
|
+
def initialize(str)
|
74
|
+
super %(Collection "#{str}" is not a valid name, might be reserved)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class FieldIdCannotBeExcludedFromIndex < Error
|
79
|
+
def initialize
|
80
|
+
super %(Field _id cannot be excluded from the index)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class CouldNotFindPathToFromIndex < Error
|
85
|
+
def initialize(str)
|
86
|
+
super %(Could not find path_to from index #{str})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class CouldNotFindPathToFromIndex < Error
|
91
|
+
def initialize(index, id)
|
92
|
+
super %(Unknown index #{index} in document #{id})
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
data/lib/jor/server.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module JOR
|
3
|
+
class Server
|
4
|
+
|
5
|
+
def initialize(redis = nil)
|
6
|
+
## defaults to test db on redis
|
7
|
+
redis ||= Redis.new(:db => 9, :driver => :hiredis)
|
8
|
+
@jor = JOR::Storage.new(redis)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
req = Rack::Request.new(env)
|
13
|
+
method = req.path
|
14
|
+
|
15
|
+
if env["REQUEST_METHOD"]!="PUT"
|
16
|
+
return [422, {"Content-Type" => "application/json"}, [{"error" => "only method accepted is PUT"}.to_json]]
|
17
|
+
end
|
18
|
+
|
19
|
+
clean_methods = method.gsub("/","").split(".")
|
20
|
+
clean_methods.map!(&:to_sym)
|
21
|
+
|
22
|
+
args = req.params["args"]
|
23
|
+
clean_args = []
|
24
|
+
body_str = req.body.read
|
25
|
+
clean_args = JSON::parse(body_str) unless body_str.nil? || body_str.empty?
|
26
|
+
|
27
|
+
begin
|
28
|
+
obj = @jor
|
29
|
+
res = nil
|
30
|
+
|
31
|
+
clean_methods.each_with_index do |meth, i|
|
32
|
+
if i==clean_methods.size()-1
|
33
|
+
res = obj.public_send(meth,*clean_args)
|
34
|
+
else
|
35
|
+
obj = obj.public_send(meth)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if res.class==Hash || res.class==Array
|
40
|
+
return [200, {"Content-Type" => "application/json"}, [res.to_json]]
|
41
|
+
else
|
42
|
+
return [200, {"Content-Type" => "application/json"}, [{"value" => res}.to_json]]
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
45
|
+
return [422, {"Content-Type" => "application/json"}, [{"error" => e.message}.to_json]]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
data/lib/jor/storage.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
module JOR
|
3
|
+
class Storage
|
4
|
+
|
5
|
+
NAMESPACE = "jor"
|
6
|
+
|
7
|
+
SELECTORS = {
|
8
|
+
:compare => ["$gt","$gte","$lt","$lte"],
|
9
|
+
:sets => ["$in","$all","$not"]
|
10
|
+
}
|
11
|
+
|
12
|
+
SELECTORS_ALL = SELECTORS.keys.inject([]) { |sel, element| sel | SELECTORS[element] }
|
13
|
+
|
14
|
+
def initialize(redis_client = nil)
|
15
|
+
redis_client.nil? ? @redis = Redis.new() : @redis = redis_client
|
16
|
+
end
|
17
|
+
|
18
|
+
def redis
|
19
|
+
@redis
|
20
|
+
end
|
21
|
+
|
22
|
+
def collections
|
23
|
+
redis.smembers("#{Storage::NAMESPACE}/collections")
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_collection(name, options = {:auto_increment => false})
|
27
|
+
options = {:auto_increment => false}.merge(options.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo})
|
28
|
+
raise CollectionNotValid.new(name) if self.respond_to?(name)
|
29
|
+
is_new = redis.sadd("#{Storage::NAMESPACE}/collections",name)
|
30
|
+
raise CollectionAlreadyExists.new(name) if (is_new==false or is_new==0)
|
31
|
+
redis.set("#{Storage::NAMESPACE}/collection/#{name}/auto-increment", options[:auto_increment])
|
32
|
+
name
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy_collection(name)
|
36
|
+
coll_to_be_removed = find_collection(name)
|
37
|
+
coll_to_be_removed.delete({})
|
38
|
+
redis.pipelined do
|
39
|
+
redis.srem("#{Storage::NAMESPACE}/collections",name)
|
40
|
+
redis.del("#{Storage::NAMESPACE}/collection/#{name}/auto-increment")
|
41
|
+
end
|
42
|
+
name
|
43
|
+
end
|
44
|
+
|
45
|
+
def destroy_all()
|
46
|
+
collections.each do |col|
|
47
|
+
destroy_collection(col)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def info
|
52
|
+
res = {}
|
53
|
+
ri = redis.info
|
54
|
+
|
55
|
+
res["used_memory_in_redis"] = ri["used_memory"].to_i
|
56
|
+
res["num_collections"] = collections.size
|
57
|
+
|
58
|
+
res["collections"] = {}
|
59
|
+
collections.each do |c|
|
60
|
+
coll = find_collection(c)
|
61
|
+
res["collections"][coll.name] = {}
|
62
|
+
res["collections"][coll.name]["num_documents"] = coll.count
|
63
|
+
res["collections"][coll.name]["auto_increment"] = coll.auto_increment?
|
64
|
+
end
|
65
|
+
|
66
|
+
res
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def method_missing(method)
|
72
|
+
find_collection(method)
|
73
|
+
end
|
74
|
+
|
75
|
+
def find_collection(method)
|
76
|
+
redis_auto_incr = redis.get("#{Storage::NAMESPACE}/collection/#{method}/auto-increment")
|
77
|
+
if (redis_auto_incr=="true")
|
78
|
+
auto_increment = true
|
79
|
+
elsif (redis_auto_incr=="false")
|
80
|
+
auto_increment = false
|
81
|
+
else
|
82
|
+
raise CollectionDoesNotExist.new(method.to_s)
|
83
|
+
end
|
84
|
+
Collection.new(self, method, auto_increment)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/lib/jor/version.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'json'
|
4
|
+
require 'hiredis'
|
5
|
+
require 'redis'
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
8
|
+
Dir[File.dirname(__FILE__) + '/test_helpers/**/*.rb'].each { |file| require file }
|
9
|
+
Dir[File.dirname(__FILE__) + '/unit/test_case.rb'].each { |file| require file }
|
10
|
+
|
11
|
+
require 'jor'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module TestHelpers
|
2
|
+
module Fixtures
|
3
|
+
|
4
|
+
def create_sample_doc_cs(partial_doc = {})
|
5
|
+
doc = {
|
6
|
+
"_id" => 1,
|
7
|
+
"name" => {
|
8
|
+
"first" => "John",
|
9
|
+
"last" => "Backus"
|
10
|
+
},
|
11
|
+
"birth" => Time.mktime("1924","12","03","05","00","00").to_i,
|
12
|
+
"death" => Time.mktime("2007","03","17","04","00","00").to_i,
|
13
|
+
"contribs" => [ "Fortran", "ALGOL", "Backus-Naur Form", "FP" ],
|
14
|
+
"awards" => [
|
15
|
+
{
|
16
|
+
"award" => "W.W. McDowellAward",
|
17
|
+
"year" => 1967,
|
18
|
+
"by" => "IEEE Computer Society"
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"award" => "National Medal of Science",
|
22
|
+
"year" => 1975,
|
23
|
+
"by" => "National Science Foundation"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"award" => "Turing Award",
|
27
|
+
"year" => 1977,
|
28
|
+
"by" => "ACM"
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"award" => "Draper Prize",
|
32
|
+
"year" => 1993,
|
33
|
+
"by" => "National Academy of Engineering"
|
34
|
+
}
|
35
|
+
]
|
36
|
+
}
|
37
|
+
doc.merge(partial_doc)
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_sample_doc_restaurant(partial_doc = {})
|
41
|
+
doc = {
|
42
|
+
"_id" => 1,
|
43
|
+
"name" => "restaurant",
|
44
|
+
"stars" => 3,
|
45
|
+
"cuisine" => ["asian", "japanese"],
|
46
|
+
"address" => {
|
47
|
+
"address" => "Main St 100",
|
48
|
+
"city" => "Ann Arbor",
|
49
|
+
"zipcode" => "08104"
|
50
|
+
},
|
51
|
+
"description" => "very long description that we might not want to index",
|
52
|
+
"wines" => [
|
53
|
+
{
|
54
|
+
"name" => "wine1",
|
55
|
+
"year" => 1998,
|
56
|
+
"type" => ["garnatxa", "merlot"]
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"name" => "wine2",
|
60
|
+
"year" => 2009,
|
61
|
+
"type" => ["syrah", "merlot"]
|
62
|
+
},
|
63
|
+
]
|
64
|
+
}
|
65
|
+
doc.merge(partial_doc)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Test::Unit::TestCase.send(:include, TestHelpers::Fixtures)
|
@@ -0,0 +1,884 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class CollectionTest < JOR::Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@jor.create_collection("test")
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_basic_insert_and_find_path
|
11
|
+
|
12
|
+
doc1 = create_sample_doc_restaurant({"_id" => 1})
|
13
|
+
@jor.test.insert(doc1)
|
14
|
+
|
15
|
+
doc2 = create_sample_doc_restaurant({"_id" => 2})
|
16
|
+
@jor.test.insert(doc2)
|
17
|
+
|
18
|
+
doc3 = create_sample_doc_restaurant({"_id" => 3})
|
19
|
+
@jor.test.insert(doc3)
|
20
|
+
|
21
|
+
assert_equal 3, @jor.test.count()
|
22
|
+
assert_equal 3, @jor.test.find({}).size
|
23
|
+
|
24
|
+
assert_equal doc1.to_json, @jor.test.find({"_id" => 1}).first.to_json
|
25
|
+
assert_equal doc2.to_json, @jor.test.find({"_id" => 2}).first.to_json
|
26
|
+
assert_equal doc3.to_json, @jor.test.find({"_id" => 3}).first.to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_bulk_insert
|
30
|
+
|
31
|
+
sample_docs = []
|
32
|
+
10.times do |i|
|
33
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}"})
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_equal 10, @jor.test.count()
|
37
|
+
|
38
|
+
docs = @jor.test.find({})
|
39
|
+
10.times do |i|
|
40
|
+
assert_equal sample_docs[i].to_json, docs[i].to_json
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_delete
|
46
|
+
sample_docs = []
|
47
|
+
10.times do |i|
|
48
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => "bar", "year" => 2000+i, "num" => 666 })
|
49
|
+
end
|
50
|
+
|
51
|
+
assert_equal 10, @jor.test.count()
|
52
|
+
|
53
|
+
assert_equal 0, @jor.test.delete({"_id" => 42})
|
54
|
+
assert_equal 10, @jor.test.count()
|
55
|
+
|
56
|
+
assert_equal 0, @jor.test.delete({"foo" => "not_bar"})
|
57
|
+
assert_equal 10, @jor.test.count()
|
58
|
+
|
59
|
+
assert_equal 1, @jor.test.delete({"_id" => 0})
|
60
|
+
assert_equal 9, @jor.test.count()
|
61
|
+
|
62
|
+
assert_equal 3, @jor.test.delete({"year" => { "$lt" => 2004 }})
|
63
|
+
assert_equal 6, @jor.test.count()
|
64
|
+
|
65
|
+
assert_equal ["4","5","6","7","8","9"].sort, @jor.redis.smembers("#{JOR::Storage::NAMESPACE}/test/idx/!/foo/String/bar").sort
|
66
|
+
assert_equal ["4","5","6","7","8","9"].sort, @jor.redis.smembers("#{JOR::Storage::NAMESPACE}/test/idx/!/num/Numeric/666").sort
|
67
|
+
assert_equal ["4","5","6","7","8","9"].sort, @jor.redis.zrange("#{JOR::Storage::NAMESPACE}/test/idx/!/num/Numeric",0,-1).sort
|
68
|
+
|
69
|
+
assert_equal 6, @jor.test.delete({"foo" => "bar"})
|
70
|
+
assert_equal 0, @jor.test.count()
|
71
|
+
|
72
|
+
assert_equal [], @jor.redis.smembers("#{JOR::Storage::NAMESPACE}/test/idx/!/num/String/bar")
|
73
|
+
assert_equal [], @jor.redis.smembers("#{JOR::Storage::NAMESPACE}/test/idx/!/num/Numeric/666")
|
74
|
+
assert_equal [].sort, @jor.redis.zrange("#{JOR::Storage::NAMESPACE}/test/idx/!/num/Numeric",0,-1).sort
|
75
|
+
|
76
|
+
assert_equal @jor.redis.keys("#{JOR::Storage::NAMESPACE}/test/idx/*"), []
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_find_exact_string
|
81
|
+
sample_docs = []
|
82
|
+
10.times do |i|
|
83
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}"})
|
84
|
+
end
|
85
|
+
|
86
|
+
doc = @jor.test.find({"name" => "foo_5"}).first
|
87
|
+
assert_equal sample_docs[5].to_json, doc.to_json
|
88
|
+
|
89
|
+
doc = @jor.test.find({"name" => "foo_7"}).first
|
90
|
+
assert_equal sample_docs[7].to_json, doc.to_json
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_find_empty
|
94
|
+
assert_equal [], @jor.test.find({})
|
95
|
+
assert_equal [], @jor.test.find({"year" => 200})
|
96
|
+
assert_equal [], @jor.test.find({"_id" => 200})
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_find_by_comparison_selector
|
100
|
+
|
101
|
+
sample_docs = []
|
102
|
+
## years from 2000 to 2009
|
103
|
+
10.times do |i|
|
104
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "year" => 2000+i})
|
105
|
+
end
|
106
|
+
|
107
|
+
doc = @jor.test.find({"year" => 2005}).first
|
108
|
+
assert_equal sample_docs[5].to_json, doc.to_json
|
109
|
+
|
110
|
+
doc = @jor.test.find({"year" => { "$lt" => 2005 }})
|
111
|
+
assert_equal 5, doc.size
|
112
|
+
assert_equal sample_docs[0].to_json, doc.first.to_json
|
113
|
+
assert_equal sample_docs[4].to_json, doc.last.to_json
|
114
|
+
|
115
|
+
doc = @jor.test.find({"year" => { "$lte" => 2005 }})
|
116
|
+
assert_equal 6, doc.size
|
117
|
+
assert_equal sample_docs[0].to_json, doc.first.to_json
|
118
|
+
assert_equal sample_docs[5].to_json, doc.last.to_json
|
119
|
+
|
120
|
+
doc = @jor.test.find({"year" => { "$gt" => 2007 }})
|
121
|
+
assert_equal 2, doc.size
|
122
|
+
assert_equal sample_docs[8].to_json, doc.first.to_json
|
123
|
+
assert_equal sample_docs[9].to_json, doc.last.to_json
|
124
|
+
|
125
|
+
doc = @jor.test.find({"year" => { "$gte" => 2007 }})
|
126
|
+
assert_equal 3, doc.size
|
127
|
+
assert_equal sample_docs[7].to_json, doc.first.to_json
|
128
|
+
assert_equal sample_docs[9].to_json, doc.last.to_json
|
129
|
+
|
130
|
+
doc = @jor.test.find({"year" => { "$gte" => 2003, "$lt" => 2005 }})
|
131
|
+
assert_equal 2, doc.size
|
132
|
+
assert_equal sample_docs[3].to_json, doc.first.to_json
|
133
|
+
assert_equal sample_docs[4].to_json, doc.last.to_json
|
134
|
+
|
135
|
+
doc = @jor.test.find({"year" => { "$gt" => 2003, "$lt" => 9999 }})
|
136
|
+
assert_equal 6, doc.size
|
137
|
+
assert_equal sample_docs[4].to_json, doc.first.to_json
|
138
|
+
assert_equal sample_docs[9].to_json, doc.last.to_json
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_find_by_comparison_combined
|
143
|
+
|
144
|
+
sample_docs = []
|
145
|
+
## years from 2000 to 2009
|
146
|
+
10.times do |i|
|
147
|
+
sample_docs << @jor.test.insert({"_id" => i, "year" => 2000+i, "desc" => "bar", "nested" => {"name" => "foo_#{i}", "quantity" => i.to_f}})
|
148
|
+
end
|
149
|
+
|
150
|
+
docs = @jor.test.find({"year" => { "$gt" => 2001, "$lt" => 2009 }, "nested" => {"quantity" => {"$lt" => 1.0}}})
|
151
|
+
assert_equal 0, docs.size
|
152
|
+
assert_equal [], docs
|
153
|
+
|
154
|
+
docs = @jor.test.find({"year" => { "$gt" => 2001, "$lt" => 2009 }, "nested" => {"quantity" => {"$lt" => 4.0}}})
|
155
|
+
assert_equal 2, docs.size
|
156
|
+
assert_equal sample_docs[2].to_json, docs.first.to_json
|
157
|
+
assert_equal sample_docs[3].to_json, docs.last.to_json
|
158
|
+
|
159
|
+
docs = @jor.test.find({"year" => { "$gt" => 2001, "$lt" => 2009 }, "nested" => {"name" => "foo_#{4}", "quantity" => {"$lte" => 4.0}}})
|
160
|
+
assert_equal 1, docs.size
|
161
|
+
assert_equal sample_docs[4].to_json, docs.first.to_json
|
162
|
+
|
163
|
+
docs = @jor.test.find({"year" => { "$gt" => 2001, "$lt" => 2009 }, "desc" => "bar", "nested" => {"name" => "foo_#{4}", "quantity" => {"$lte" => 4.0}}})
|
164
|
+
assert_equal 1, docs.size
|
165
|
+
assert_equal sample_docs[4].to_json, docs.first.to_json
|
166
|
+
|
167
|
+
docs = @jor.test.find({"year" => { "$gt" => 2001, "$lt" => 2009 }, "desc" => "NOT_bar", "nested" => {"name" => "foo_#{4}", "quantity" => {"$lte" => 4.0}}})
|
168
|
+
assert_equal 0, docs.size
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_find_by_set_selector
|
173
|
+
|
174
|
+
sample_docs = []
|
175
|
+
## years from 2000 to 2009
|
176
|
+
10.times do |i|
|
177
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "nested" => { "year" => 2000+i, "pair" => ((i%2)==0 ? "even" : "odd")} })
|
178
|
+
end
|
179
|
+
|
180
|
+
docs = @jor.test.find({"_id" => {"$in" => []}})
|
181
|
+
assert_equal 0, docs.size
|
182
|
+
|
183
|
+
docs = @jor.test.find({"_id" => {"$in" => [42]}})
|
184
|
+
assert_equal 0, docs.size
|
185
|
+
|
186
|
+
docs = @jor.test.find({"_id" => {"$in" => [8]}})
|
187
|
+
assert_equal 1, docs.size
|
188
|
+
assert_equal sample_docs[8].to_json, docs.first.to_json
|
189
|
+
|
190
|
+
docs = @jor.test.find({"_id" => {"$all" => [8]}})
|
191
|
+
assert_equal 1, docs.size
|
192
|
+
assert_equal sample_docs[8].to_json, docs.first.to_json
|
193
|
+
|
194
|
+
docs = @jor.test.find({"_id" => {"$in" => [1, 2, 3, 4, 42]}})
|
195
|
+
assert_equal 4, docs.size
|
196
|
+
assert_equal sample_docs[1].to_json, docs.first.to_json
|
197
|
+
assert_equal sample_docs[4].to_json, docs.last.to_json
|
198
|
+
|
199
|
+
docs = @jor.test.find({"_id" => {"$all" => [1, 2, 3, 4, 42]}})
|
200
|
+
assert_equal 0, docs.size
|
201
|
+
|
202
|
+
docs = @jor.test.find({"name" => {"$in" => ["foo_42"]}})
|
203
|
+
assert_equal 0, docs.size
|
204
|
+
|
205
|
+
docs = @jor.test.find({"name" => {"$all" => ["foo_42"]}})
|
206
|
+
assert_equal 0, docs.size
|
207
|
+
|
208
|
+
docs = @jor.test.find({"name" => {"$in" => []}})
|
209
|
+
assert_equal 0, docs.size
|
210
|
+
|
211
|
+
docs = @jor.test.find({"name" => {"$all" => []}})
|
212
|
+
assert_equal 0, docs.size
|
213
|
+
|
214
|
+
docs = @jor.test.find({"name" => {"$in" => ["foo_7", "foo_8", "foo_42"]}})
|
215
|
+
assert_equal 2, docs.size
|
216
|
+
assert_equal sample_docs[7].to_json, docs.first.to_json
|
217
|
+
assert_equal sample_docs[8].to_json, docs.last.to_json
|
218
|
+
|
219
|
+
docs = @jor.test.find({"nested" => {"pair" => { "$in" => ["even", "odd"]}}})
|
220
|
+
assert_equal 10, docs.size
|
221
|
+
assert_equal sample_docs[0].to_json, docs.first.to_json
|
222
|
+
assert_equal sample_docs[9].to_json, docs.last.to_json
|
223
|
+
|
224
|
+
docs = @jor.test.find({"nested" => {"pair" => { "$all" => ["even", "odd"]}}})
|
225
|
+
assert_equal 0, docs.size
|
226
|
+
|
227
|
+
docs = @jor.test.find({"nested" => {"pair" => { "$in" => ["even"]}}})
|
228
|
+
assert_equal 5, docs.size
|
229
|
+
assert_equal sample_docs[0].to_json, docs.first.to_json
|
230
|
+
assert_equal sample_docs[8].to_json, docs.last.to_json
|
231
|
+
|
232
|
+
docs = @jor.test.find({"nested" => {"pair" => { "$all" => ["even"]}}})
|
233
|
+
assert_equal 5, docs.size
|
234
|
+
assert_equal sample_docs[0].to_json, docs.first.to_json
|
235
|
+
assert_equal sample_docs[8].to_json, docs.last.to_json
|
236
|
+
|
237
|
+
docs = @jor.test.find({"nested" => {"pair" => { "$in" => ["even", "fake"]}}})
|
238
|
+
assert_equal 5, docs.size
|
239
|
+
assert_equal sample_docs[0].to_json, docs.first.to_json
|
240
|
+
assert_equal sample_docs[8].to_json, docs.last.to_json
|
241
|
+
|
242
|
+
docs = @jor.test.find({"nested" => {"pair" => { "$all" => ["even", "fake"]}}})
|
243
|
+
assert_equal 0, docs.size
|
244
|
+
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_find_by_not_selector
|
248
|
+
|
249
|
+
sample_docs = []
|
250
|
+
## years from 2000 to 2009
|
251
|
+
10.times do |i|
|
252
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "nested" => { "year" => 2000+i, "even" => ((i%2)==0 ? true : false)} })
|
253
|
+
end
|
254
|
+
|
255
|
+
docs = @jor.test.find({"_id" => {"$not" => 3}})
|
256
|
+
assert_equal 9, docs.size
|
257
|
+
docs.each do |doc|
|
258
|
+
assert_not_equal 3, doc["_id"]
|
259
|
+
end
|
260
|
+
|
261
|
+
docs = @jor.test.find({"_id" => {"$not" => [3]}})
|
262
|
+
assert_equal 9, docs.size
|
263
|
+
docs.each do |doc|
|
264
|
+
assert_not_equal 3, doc["_id"]
|
265
|
+
end
|
266
|
+
|
267
|
+
docs = @jor.test.find({"_id" => {"$not" => [1, 3, 4, 42]}})
|
268
|
+
assert_equal 7, docs.size
|
269
|
+
docs.each do |doc|
|
270
|
+
assert_not_equal 1, doc["_id"]
|
271
|
+
assert_not_equal 3, doc["_id"]
|
272
|
+
assert_not_equal 4, doc["_id"]
|
273
|
+
assert_not_equal 42, doc["_id"]
|
274
|
+
end
|
275
|
+
|
276
|
+
docs = @jor.test.find({"_id" => {"$not" => [3]}})
|
277
|
+
assert_equal 9, docs.size
|
278
|
+
docs.each do |doc|
|
279
|
+
assert_not_equal 3, doc["_id"]
|
280
|
+
end
|
281
|
+
|
282
|
+
docs = @jor.test.find({"name" => {"$not" => "foo_3"}})
|
283
|
+
assert_equal 9, docs.size
|
284
|
+
docs.each do |doc|
|
285
|
+
assert_not_equal 3, doc["_id"]
|
286
|
+
end
|
287
|
+
|
288
|
+
docs = @jor.test.find({"name" => {"$not" => ["foo_3"]}})
|
289
|
+
assert_equal 9, docs.size
|
290
|
+
docs.each do |doc|
|
291
|
+
assert_not_equal 3, doc["_id"]
|
292
|
+
end
|
293
|
+
|
294
|
+
docs = @jor.test.find({"name" => {"$not" => ["foo_1", "foo_3", "foo_4", "foo_42"]}})
|
295
|
+
assert_equal 7, docs.size
|
296
|
+
docs.each do |doc|
|
297
|
+
assert_not_equal 1, doc["_id"]
|
298
|
+
assert_not_equal 3, doc["_id"]
|
299
|
+
assert_not_equal 4, doc["_id"]
|
300
|
+
assert_not_equal 42, doc["_id"]
|
301
|
+
end
|
302
|
+
|
303
|
+
docs = @jor.test.find({"nested" => {"year" => {"$not" => 2004}}})
|
304
|
+
assert_equal 9, docs.size
|
305
|
+
docs.each do |doc|
|
306
|
+
assert_not_equal 4, doc["_id"]
|
307
|
+
end
|
308
|
+
|
309
|
+
docs = @jor.test.find({"nested" => {"year" => {"$not" => [2004, 2009]}}})
|
310
|
+
assert_equal 8, docs.size
|
311
|
+
docs.each do |doc|
|
312
|
+
assert_not_equal 4, doc["_id"]
|
313
|
+
assert_not_equal 9, doc["_id"]
|
314
|
+
end
|
315
|
+
|
316
|
+
docs = @jor.test.find({"nested" => {"even" => true}})
|
317
|
+
assert_equal 5, docs.size
|
318
|
+
docs.each do |doc|
|
319
|
+
assert_equal 0, doc["_id"]%2
|
320
|
+
end
|
321
|
+
|
322
|
+
docs = @jor.test.find({"nested" => {"even" => {"$not" => false}}})
|
323
|
+
assert_equal 5, docs.size
|
324
|
+
docs.each do |doc|
|
325
|
+
assert_equal 0, doc["_id"]%2
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
|
330
|
+
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_playing_with_find_options
|
334
|
+
|
335
|
+
n = (JOR::Collection::DEFAULT_OPTIONS[:max_documents]+100)
|
336
|
+
|
337
|
+
n.times do |i|
|
338
|
+
doc = create_sample_doc_restaurant({"_id" => i})
|
339
|
+
@jor.test.insert(doc)
|
340
|
+
end
|
341
|
+
|
342
|
+
## testing max_documents
|
343
|
+
|
344
|
+
docs = @jor.test.find({})
|
345
|
+
|
346
|
+
assert_equal JOR::Collection::DEFAULT_OPTIONS[:max_documents], docs.size
|
347
|
+
assert_equal 0, docs.first["_id"]
|
348
|
+
assert_equal JOR::Collection::DEFAULT_OPTIONS[:max_documents]-1, docs.last["_id"]
|
349
|
+
|
350
|
+
docs = @jor.test.find({},{:max_documents => 20})
|
351
|
+
assert_equal 20, docs.size
|
352
|
+
|
353
|
+
docs = @jor.test.find({},{:max_documents => -1})
|
354
|
+
assert_equal n, docs.size
|
355
|
+
assert_equal 0, docs.first["_id"]
|
356
|
+
assert_equal n-1, docs.last["_id"]
|
357
|
+
|
358
|
+
## testing only_ids
|
359
|
+
|
360
|
+
docs = @jor.test.find({},{:only_ids => true, :max_documents => -1})
|
361
|
+
assert_equal n, docs.size
|
362
|
+
assert_equal 0, docs.first
|
363
|
+
assert_equal n-1, docs.last
|
364
|
+
|
365
|
+
docs = @jor.test.find({},{:only_ids => true})
|
366
|
+
assert_equal JOR::Collection::DEFAULT_OPTIONS[:max_documents], docs.size
|
367
|
+
assert_equal 0, docs.first
|
368
|
+
assert_equal JOR::Collection::DEFAULT_OPTIONS[:max_documents]-1, docs.last
|
369
|
+
|
370
|
+
## testing reversed
|
371
|
+
|
372
|
+
docs = @jor.test.find({},{:only_ids => true, :max_documents => -1, :reversed => true})
|
373
|
+
assert_equal n, docs.size
|
374
|
+
assert_equal n-1, docs.first
|
375
|
+
assert_equal 0, docs.last
|
376
|
+
|
377
|
+
docs = @jor.test.find({},{:only_ids => true, :reversed => true})
|
378
|
+
assert_equal JOR::Collection::DEFAULT_OPTIONS[:max_documents], docs.size
|
379
|
+
assert_equal n-1, docs.first
|
380
|
+
assert_equal n-JOR::Collection::DEFAULT_OPTIONS[:max_documents], docs.last
|
381
|
+
|
382
|
+
## encoded false
|
383
|
+
|
384
|
+
docs = @jor.test.find({},{:raw => true, :reversed => true})
|
385
|
+
assert_equal JOR::Collection::DEFAULT_OPTIONS[:max_documents], docs.size
|
386
|
+
assert_equal String, docs.first.class
|
387
|
+
assert_equal String, docs.last.class
|
388
|
+
assert_equal n-1, JSON::parse(docs.first)["_id"]
|
389
|
+
assert_equal n-JOR::Collection::DEFAULT_OPTIONS[:max_documents], JSON::parse(docs.last)["_id"]
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
def test_exclude_indexes
|
394
|
+
|
395
|
+
assert_raise JOR::FieldIdCannotBeExcludedFromIndex do
|
396
|
+
@jor.test.insert(create_sample_doc_restaurant({"_id" => 1}),
|
397
|
+
{:excluded_fields_to_index => {"_id" => true}})
|
398
|
+
end
|
399
|
+
|
400
|
+
@jor.test.insert(create_sample_doc_restaurant({"_id" => 1}),
|
401
|
+
{:excluded_fields_to_index => {"description" => true}})
|
402
|
+
|
403
|
+
@jor.test.insert(create_sample_doc_restaurant({"_id" => 42}),
|
404
|
+
{:excluded_fields_to_index => {}})
|
405
|
+
|
406
|
+
v = []
|
407
|
+
@jor.test.indexes(1).each do |ind|
|
408
|
+
v << ind["path"]
|
409
|
+
end
|
410
|
+
assert_equal false, v.include?("/description")
|
411
|
+
|
412
|
+
v = []
|
413
|
+
@jor.test.indexes(42).each do |ind|
|
414
|
+
v << ind["path"]
|
415
|
+
end
|
416
|
+
assert_equal true, v.include?("/description")
|
417
|
+
|
418
|
+
res = @jor.test.find({},{:reversed => true})
|
419
|
+
assert_equal 2, res.size
|
420
|
+
assert_equal "very long description that we might not want to index", res.first["description"]
|
421
|
+
assert_equal 42, res.first["_id"]
|
422
|
+
assert_equal "very long description that we might not want to index", res.last["description"]
|
423
|
+
assert_equal 1, res.last["_id"]
|
424
|
+
|
425
|
+
res = @jor.test.find({"description" => "very long description that we might not want to index"}, :reversed => true)
|
426
|
+
assert_equal 1, res.size
|
427
|
+
assert_equal 42, res.first["_id"]
|
428
|
+
|
429
|
+
end
|
430
|
+
|
431
|
+
def test_auto_increment_collections
|
432
|
+
@jor.create_collection("no_auto_increment")
|
433
|
+
@jor.create_collection("no_auto_increment2", :auto_increment => false)
|
434
|
+
@jor.create_collection("auto_increment",:auto_increment => true)
|
435
|
+
|
436
|
+
assert_equal false, @jor.no_auto_increment.auto_increment?
|
437
|
+
assert_equal false, @jor.no_auto_increment2.auto_increment?
|
438
|
+
assert_equal true, @jor.auto_increment.auto_increment?
|
439
|
+
|
440
|
+
10.times do |i|
|
441
|
+
@jor.auto_increment.insert({"foo" => "bar"})
|
442
|
+
end
|
443
|
+
|
444
|
+
assert_equal 10, @jor.auto_increment.count()
|
445
|
+
|
446
|
+
assert_raise JOR::DocumentDoesNotNeedId do
|
447
|
+
@jor.auto_increment.insert({"_id"=> 10, "foo" => "bar"})
|
448
|
+
end
|
449
|
+
|
450
|
+
assert_equal 10, @jor.auto_increment.count()
|
451
|
+
assert_equal 10, @jor.auto_increment.last_id()
|
452
|
+
assert_equal 0, @jor.no_auto_increment.last_id()
|
453
|
+
end
|
454
|
+
|
455
|
+
def test_last_id_for_collections
|
456
|
+
@jor.create_collection("no_auto_increment")
|
457
|
+
@jor.create_collection("auto_increment",:auto_increment => true)
|
458
|
+
|
459
|
+
assert_equal 0, @jor.no_auto_increment.last_id()
|
460
|
+
assert_equal 0, @jor.auto_increment.last_id()
|
461
|
+
|
462
|
+
10.times do |i|
|
463
|
+
@jor.auto_increment.insert({"foo" => "bar"})
|
464
|
+
end
|
465
|
+
|
466
|
+
assert_equal 10, @jor.auto_increment.last_id()
|
467
|
+
assert_not_nil @jor.auto_increment.find({"_id" => 10}).first
|
468
|
+
|
469
|
+
10.times do |i|
|
470
|
+
@jor.no_auto_increment.insert({"_id" => i+10, "foo" => "bar"})
|
471
|
+
end
|
472
|
+
|
473
|
+
assert_equal 19, @jor.no_auto_increment.last_id()
|
474
|
+
assert_not_nil @jor.no_auto_increment.find({"_id" => 10}).first
|
475
|
+
end
|
476
|
+
|
477
|
+
def test_ids_expections_for_collections
|
478
|
+
@jor.create_collection("no_auto_increment")
|
479
|
+
@jor.create_collection("auto_increment",:auto_increment => true)
|
480
|
+
|
481
|
+
assert_raise JOR::DocumentDoesNotNeedId do
|
482
|
+
@jor.auto_increment.insert({"_id"=> 10, "foo" => "bar"})
|
483
|
+
end
|
484
|
+
|
485
|
+
assert_raise JOR::DocumentNeedsId do
|
486
|
+
@jor.no_auto_increment.insert({"foo" => "bar"})
|
487
|
+
end
|
488
|
+
|
489
|
+
assert_raise JOR::InvalidDocumentId do
|
490
|
+
@jor.no_auto_increment.insert({"_id"=> "10", "foo" => "bar"})
|
491
|
+
end
|
492
|
+
|
493
|
+
assert_raise JOR::InvalidDocumentId do
|
494
|
+
@jor.no_auto_increment.insert({"_id"=> -1, "foo" => "bar"})
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def test_ids_will_be_sorted
|
499
|
+
v = [1, 10, 100, 1000, 10000, 2, 20, 200, 2000, 20000]
|
500
|
+
v_sorted = v.sort
|
501
|
+
v_shuffled = v.shuffle
|
502
|
+
|
503
|
+
v_shuffled.each do |val|
|
504
|
+
@jor.test.insert({"_id" => val, "foo" => "bar"})
|
505
|
+
end
|
506
|
+
|
507
|
+
res = @jor.test.find({})
|
508
|
+
assert_equal v.size, res.size
|
509
|
+
|
510
|
+
res.each_with_index do |item, i|
|
511
|
+
assert_equal v_sorted[i], item["_id"]
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
def test_concurrent_inserts
|
516
|
+
|
517
|
+
threads = []
|
518
|
+
inserted_by_thread = []
|
519
|
+
5.times do |i|
|
520
|
+
inserted_by_thread[i] = []
|
521
|
+
threads << Thread.new {
|
522
|
+
id = i
|
523
|
+
1000.times do |j|
|
524
|
+
begin
|
525
|
+
doc = @jor.test.insert(create_sample_doc_restaurant({"_id" => j}))
|
526
|
+
inserted_by_thread[id] << j unless doc.nil?
|
527
|
+
sleep(0.1) if (j%200==0)
|
528
|
+
rescue Exception => e
|
529
|
+
end
|
530
|
+
end
|
531
|
+
}
|
532
|
+
end
|
533
|
+
|
534
|
+
threads.each do |t|
|
535
|
+
t.join()
|
536
|
+
end
|
537
|
+
|
538
|
+
res = @jor.test.find({},{:max_documents => -1})
|
539
|
+
assert_equal 1000, res.size
|
540
|
+
|
541
|
+
all = inserted_by_thread[0]
|
542
|
+
inserted_by_thread.each do |curr|
|
543
|
+
all = all & curr
|
544
|
+
end
|
545
|
+
assert_equal 0, all.size
|
546
|
+
|
547
|
+
all = inserted_by_thread[0]
|
548
|
+
inserted_by_thread.each do |curr|
|
549
|
+
all = all | curr
|
550
|
+
end
|
551
|
+
assert_equal 1000, all.size
|
552
|
+
end
|
553
|
+
|
554
|
+
def test_intervals
|
555
|
+
1000.times do |i|
|
556
|
+
@jor.test.insert(create_sample_doc_restaurant({"_id" => i, "at" => i}))
|
557
|
+
end
|
558
|
+
|
559
|
+
docs = @jor.test.find({})
|
560
|
+
assert_equal 1000, docs.size
|
561
|
+
|
562
|
+
docs = @jor.test.find({"at" => {"$lt" => 100}})
|
563
|
+
assert_equal 100, docs.size
|
564
|
+
|
565
|
+
docs = @jor.test.find({"at" => {"$lt" => 100, "$gte" => 50}})
|
566
|
+
assert_equal 50, docs.size
|
567
|
+
|
568
|
+
curr = 50
|
569
|
+
docs.each do |doc|
|
570
|
+
assert_equal curr, doc["_id"]
|
571
|
+
curr+=1
|
572
|
+
end
|
573
|
+
|
574
|
+
docs = @jor.test.find({"at" => {"$lt" => 100, "$gte" => 150}})
|
575
|
+
assert_equal 0, docs.size
|
576
|
+
end
|
577
|
+
|
578
|
+
def test_update
|
579
|
+
sample_docs = []
|
580
|
+
5.times do |i|
|
581
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => "bar", "year" => 2000+i })
|
582
|
+
end
|
583
|
+
|
584
|
+
@jor.test.update({"name" => "foo_4"}, {"name" => "foo_changed_4", "additional_field" => 3})
|
585
|
+
|
586
|
+
docs = @jor.test.find({"name" => "foo_4"})
|
587
|
+
assert_equal 0, docs.size()
|
588
|
+
|
589
|
+
[{"additional_field" => 3}, {"name" => "foo_changed_4"}, {"year" => 2004}].each do |search_doc|
|
590
|
+
docs = @jor.test.find(search_doc)
|
591
|
+
assert_equal 1, docs.size()
|
592
|
+
assert_equal "foo_changed_4", docs.first["name"]
|
593
|
+
assert_equal 3, docs.first["additional_field"]
|
594
|
+
assert_equal 2004, docs.first["year"]
|
595
|
+
assert_equal "bar", docs.first["foo"]
|
596
|
+
end
|
597
|
+
|
598
|
+
end
|
599
|
+
|
600
|
+
def test_update_with_id
|
601
|
+
sample_docs = []
|
602
|
+
5.times do |i|
|
603
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => "bar", "year" => 2000+i })
|
604
|
+
end
|
605
|
+
|
606
|
+
docs = @jor.test.update({"name" => "foo_4"}, {"name" => "foo_changed_4", "additional_field" => 3, "_id" => 666})
|
607
|
+
assert_equal 1, docs.size()
|
608
|
+
assert_equal "foo_changed_4", docs.first["name"]
|
609
|
+
assert_equal 4, docs.first["_id"]
|
610
|
+
|
611
|
+
docs = @jor.test.find({"_id" => 4})
|
612
|
+
assert_equal 1, docs.size()
|
613
|
+
assert_equal "foo_changed_4", docs.first["name"]
|
614
|
+
assert_equal 4, docs.first["_id"]
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_update_with_excluded_fields
|
618
|
+
sample_docs = []
|
619
|
+
5.times do |i|
|
620
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => "bar", "year" => 2000+i })
|
621
|
+
end
|
622
|
+
|
623
|
+
docs = @jor.test.update({"foo" => "bar"}, {"foo" => "bar_changed", "description" => "long ass description"},
|
624
|
+
{:excluded_fields_to_index => {"description" => true}})
|
625
|
+
|
626
|
+
assert_equal 5, docs.size()
|
627
|
+
assert_equal "long ass description", docs.first["description"]
|
628
|
+
assert_equal "long ass description", docs.last["description"]
|
629
|
+
|
630
|
+
docs = @jor.test.find({"foo" => "bar_changed"})
|
631
|
+
assert_equal 5, docs.size()
|
632
|
+
assert_equal "long ass description", docs.first["description"]
|
633
|
+
assert_equal "long ass description", docs.last["description"]
|
634
|
+
|
635
|
+
docs = @jor.test.find({"description" => "long ass description"})
|
636
|
+
assert_equal 0, docs.size()
|
637
|
+
|
638
|
+
docs = @jor.test.update({"foo" => "bar_changed"}, {"description" => "long ass description"})
|
639
|
+
assert_equal 5, docs.size()
|
640
|
+
|
641
|
+
docs = @jor.test.find({"description" => "long ass description"})
|
642
|
+
assert_equal 5, docs.size()
|
643
|
+
end
|
644
|
+
|
645
|
+
def test_update_massive_update
|
646
|
+
|
647
|
+
sample_docs = []
|
648
|
+
5.times do |i|
|
649
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => "bar", "year" => 2000+i })
|
650
|
+
end
|
651
|
+
|
652
|
+
docs = @jor.test.find({"foo" => "bar"})
|
653
|
+
assert_equal 5, docs.size()
|
654
|
+
|
655
|
+
docs = @jor.test.find({"foo" => "bar_changed"})
|
656
|
+
assert_equal 0, docs.size()
|
657
|
+
|
658
|
+
docs = @jor.test.find({"bar" => "bar_added"})
|
659
|
+
assert_equal 0, docs.size()
|
660
|
+
|
661
|
+
@jor.test.update({"foo" => "bar"}, {"foo" => "bar_changed", "bar" => "bar_added"})
|
662
|
+
|
663
|
+
docs = @jor.test.find({"foo" => "bar"})
|
664
|
+
assert_equal 0, docs.size()
|
665
|
+
|
666
|
+
docs = @jor.test.find({"foo" => "bar_changed"})
|
667
|
+
assert_equal 5, docs.size()
|
668
|
+
|
669
|
+
docs = @jor.test.find({"bar" => "bar_added"})
|
670
|
+
assert_equal 5, docs.size()
|
671
|
+
end
|
672
|
+
|
673
|
+
def test_update_remove_field
|
674
|
+
|
675
|
+
sample_docs = []
|
676
|
+
5.times do |i|
|
677
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => "bar", "year" => 2000+i })
|
678
|
+
end
|
679
|
+
|
680
|
+
@jor.test.update({"foo" => "bar"}, {"foo" => nil, "xtra" => "large"})
|
681
|
+
|
682
|
+
docs = @jor.test.find({"foo" => "bar"})
|
683
|
+
assert_equal 0, docs.size()
|
684
|
+
|
685
|
+
docs = @jor.test.find({})
|
686
|
+
assert_equal 5, docs.size()
|
687
|
+
|
688
|
+
docs.each_with_index do |d, i|
|
689
|
+
assert_equal "foo_#{i}", d["name"]
|
690
|
+
assert_equal i, d["_id"]
|
691
|
+
assert_equal nil, d["foo"]
|
692
|
+
assert_equal "large", d["xtra"]
|
693
|
+
end
|
694
|
+
|
695
|
+
@jor.test.update({"xtra" => "large"}, {"foo" => "bar"})
|
696
|
+
|
697
|
+
docs = @jor.test.find({"foo" => "bar"})
|
698
|
+
assert_equal 5, docs.size()
|
699
|
+
|
700
|
+
docs.each_with_index do |d, i|
|
701
|
+
assert_equal "foo_#{i}", d["name"]
|
702
|
+
assert_equal i, d["_id"]
|
703
|
+
assert_equal "bar", d["foo"]
|
704
|
+
assert_equal "large", d["xtra"]
|
705
|
+
end
|
706
|
+
|
707
|
+
end
|
708
|
+
|
709
|
+
def test_update_remove_filed_nested
|
710
|
+
|
711
|
+
@jor.test.insert(create_sample_doc_restaurant({"_id" => 42}))
|
712
|
+
docs = @jor.test.find({"address" => {"zipcode" => "08104"}})
|
713
|
+
assert_equal 1, docs.size()
|
714
|
+
|
715
|
+
indexes_before = @jor.test.indexes(42)
|
716
|
+
|
717
|
+
@jor.test.update({"_id" => 42}, {"address" => {"zipcode" => nil}})
|
718
|
+
docs = @jor.test.find({"address" => {"zipcode" => "08104"}})
|
719
|
+
assert_equal 0, docs.size
|
720
|
+
|
721
|
+
indexes_after = @jor.test.indexes(42)
|
722
|
+
## -1 because we removed address/zipcode, but plus 1 because now _updated_at exists
|
723
|
+
assert_equal indexes_before.size, indexes_after.size
|
724
|
+
indexes_after.each do |item|
|
725
|
+
assert_equal false, ["/address/zipcode"].include?(item["path"])
|
726
|
+
end
|
727
|
+
|
728
|
+
|
729
|
+
docs = @jor.test.find({"_id" => 42})
|
730
|
+
assert_equal 1, docs.size
|
731
|
+
assert_equal "Ann Arbor", docs.first["address"]["city"]
|
732
|
+
assert_equal "Main St 100", docs.first["address"]["address"]
|
733
|
+
|
734
|
+
@jor.test.update({"_id" => 42}, {"address" => nil})
|
735
|
+
docs = @jor.test.find({"address" => {"zipcode" => "08104"}})
|
736
|
+
assert_equal 0, docs.size
|
737
|
+
|
738
|
+
indexes_after = @jor.test.indexes(42)
|
739
|
+
assert_equal indexes_before.size - 2, indexes_after.size
|
740
|
+
|
741
|
+
indexes_after.each do |item|
|
742
|
+
assert_equal false, ["/address/zipcode", "/address/address", "/address/city"].include?(item["path"])
|
743
|
+
end
|
744
|
+
|
745
|
+
end
|
746
|
+
|
747
|
+
def test_update_arrays
|
748
|
+
|
749
|
+
sample_docs = []
|
750
|
+
5.times do |i|
|
751
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => [1,2,3,4,5], "year" => 2000+i })
|
752
|
+
end
|
753
|
+
|
754
|
+
@jor.test.update({"_id" => 4}, {"foo" => [6,7,8]})
|
755
|
+
docs = @jor.test.find({"_id" => 4})
|
756
|
+
assert_equal 1, docs.size()
|
757
|
+
assert_equal [6,7,8].sort, docs.first["foo"].sort
|
758
|
+
|
759
|
+
@jor.test.update({"_id" => 4}, {"foo" => {"bar" => [9, 10]}})
|
760
|
+
docs = @jor.test.find({"_id" => 4})
|
761
|
+
assert_equal 1, docs.size()
|
762
|
+
assert_equal [9, 10].sort, docs.first["foo"]["bar"].sort
|
763
|
+
|
764
|
+
@jor.test.update({"_id" => 4}, {"foo" => {"bar" => [11, 12]}})
|
765
|
+
docs = @jor.test.find({"_id" => 4})
|
766
|
+
assert_equal 1, docs.size()
|
767
|
+
assert_equal [11, 12].sort, docs.first["foo"]["bar"].sort
|
768
|
+
|
769
|
+
@jor.test.update({"_id" => 4}, {"foo" => nil})
|
770
|
+
docs = @jor.test.find({"_id" => 4})
|
771
|
+
assert_equal 1, docs.size()
|
772
|
+
assert_equal nil, docs.first["foo"]
|
773
|
+
|
774
|
+
assert_equal 0, ([{"path"=>"/name", "obj"=>"String", "value"=>"foo_4"},
|
775
|
+
{"path"=>"/_id", "obj"=>"Numeric", "value"=>"4"},
|
776
|
+
{"path"=>"/year", "obj"=>"Numeric", "value"=>"2004"}] - @jor.test.indexes(4)).size
|
777
|
+
|
778
|
+
|
779
|
+
end
|
780
|
+
|
781
|
+
def test_created_and_update_at
|
782
|
+
start_time = Time.now.to_f
|
783
|
+
sample_docs = []
|
784
|
+
5.times do |i|
|
785
|
+
sample_docs << @jor.test.insert({"_id" => i, "name" => "foo_#{i}", "foo" => [1,2,3,4,5], "year" => 2000+i })
|
786
|
+
end
|
787
|
+
end_time = Time.now.to_f
|
788
|
+
|
789
|
+
sample_docs.each do |d|
|
790
|
+
assert_equal true, d["_created_at"]>=start_time && d["_created_at"]<=end_time
|
791
|
+
end
|
792
|
+
|
793
|
+
docs = @jor.test.find({})
|
794
|
+
docs.each do |d|
|
795
|
+
assert_equal true, d["_created_at"]>=start_time && d["_created_at"]<=end_time
|
796
|
+
assert_equal nil, d["_updated_at"]
|
797
|
+
end
|
798
|
+
|
799
|
+
@jor.test.insert({"_id" => 42, "name" => "foo_#{42}", "foo" => [1,2,3,4,5], "year" => 2000+42, "_created_at" => start_time})
|
800
|
+
docs = @jor.test.find({"_id" => 42})
|
801
|
+
assert_equal start_time, docs.first["_created_at"]
|
802
|
+
|
803
|
+
start_time2 = Time.now.to_f
|
804
|
+
@jor.test.update({},{"updated" => "yeah"})
|
805
|
+
end_time2 = Time.now.to_f
|
806
|
+
|
807
|
+
docs = @jor.test.find({})
|
808
|
+
docs.each do |d|
|
809
|
+
assert_equal true, d["_created_at"]>=start_time && d["_created_at"]<=end_time
|
810
|
+
assert_equal true, d["_updated_at"]>=start_time2 && d["_updated_at"]<=end_time2
|
811
|
+
end
|
812
|
+
|
813
|
+
assert_equal 6, docs.size()
|
814
|
+
|
815
|
+
@jor.test.delete({"_created_at" => {"$lte" => start_time}})
|
816
|
+
docs = @jor.test.find({})
|
817
|
+
assert_equal 5, docs.size()
|
818
|
+
end
|
819
|
+
|
820
|
+
def test_boolean_fields
|
821
|
+
|
822
|
+
doc = @jor.test.insert({"_id" => 1, "foo" => "bar", "is_true" => true, "is_false" => false})
|
823
|
+
assert_equal true, doc["is_true"]
|
824
|
+
assert_equal false, doc["is_false"]
|
825
|
+
|
826
|
+
doc = @jor.test.insert({"_id" => 2, "foo" => "bar", "is_true" => true, "is_false" => false})
|
827
|
+
assert_equal true, doc["is_true"]
|
828
|
+
assert_equal false, doc["is_false"]
|
829
|
+
|
830
|
+
docs = @jor.test.find({})
|
831
|
+
assert_equal 2, docs.size
|
832
|
+
assert_equal true, docs.first["is_true"]
|
833
|
+
assert_equal false, docs.first["is_false"]
|
834
|
+
assert_equal true, docs.last["is_true"]
|
835
|
+
assert_equal false, docs.last["is_false"]
|
836
|
+
|
837
|
+
docs = @jor.test.find({"_id" => 2, "is_true" => true})
|
838
|
+
assert_equal 1, docs.size
|
839
|
+
assert_equal 2, docs.first["_id"]
|
840
|
+
assert_equal true, docs.first["is_true"]
|
841
|
+
assert_equal false, docs.first["is_false"]
|
842
|
+
|
843
|
+
docs = @jor.test.find({"_id" => 2, "foo" => "not_bar"})
|
844
|
+
assert_equal 0, docs.size
|
845
|
+
|
846
|
+
docs = @jor.test.find({"is_false" => false})
|
847
|
+
assert_equal 2, docs.size
|
848
|
+
|
849
|
+
docs = @jor.test.find({"_id" => 2, "is_true" => false})
|
850
|
+
assert_equal 0, docs.size
|
851
|
+
|
852
|
+
docs = @jor.test.find({"_id" => 2, "is_true" => "false"})
|
853
|
+
assert_equal 0, docs.size
|
854
|
+
|
855
|
+
docs = @jor.test.find({"_id" => 2, "is_true" => "true"})
|
856
|
+
assert_equal 0, docs.size
|
857
|
+
|
858
|
+
docs = @jor.test.find({"_id" => 2, "is_true" => nil})
|
859
|
+
assert_equal 0, docs.size
|
860
|
+
|
861
|
+
docs = @jor.test.update({"_id" => 2, "is_true" => true}, {"is_true" => false})
|
862
|
+
assert_equal 1, docs.size
|
863
|
+
assert_equal false, docs.first["is_true"]
|
864
|
+
|
865
|
+
docs = @jor.test.find({"_id" => 2})
|
866
|
+
assert_equal 1, docs.size
|
867
|
+
assert_equal 2, docs.first["_id"]
|
868
|
+
assert_equal false, docs.first["is_true"]
|
869
|
+
assert_equal false, docs.first["is_false"]
|
870
|
+
|
871
|
+
docs = @jor.test.find({"is_true" => {"$in" => [true, false]}})
|
872
|
+
assert_equal 2, docs.size
|
873
|
+
assert_equal true, docs.first["is_true"]
|
874
|
+
assert_equal false, docs.first["is_false"]
|
875
|
+
assert_equal 1, docs.first["_id"]
|
876
|
+
assert_equal false, docs.last["is_true"]
|
877
|
+
assert_equal false, docs.last["is_false"]
|
878
|
+
assert_equal 2, docs.last["_id"]
|
879
|
+
|
880
|
+
docs = @jor.test.find({"is_true" => {"$all" => [true, false]}})
|
881
|
+
assert_equal 0, docs.size
|
882
|
+
end
|
883
|
+
|
884
|
+
end
|