hikki 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +6 -0
- data/adapters/hikki-memcache/.rspec +2 -0
- data/adapters/hikki-memcache/.travis.yml +3 -0
- data/adapters/hikki-memcache/Gemfile +7 -0
- data/adapters/hikki-memcache/LICENSE.txt +22 -0
- data/adapters/hikki-memcache/README.md +50 -0
- data/adapters/hikki-memcache/Rakefile +6 -0
- data/adapters/hikki-memcache/hikki-memcache.gemspec +27 -0
- data/adapters/hikki-memcache/lib/hikki/adapters/memcache_adapter.rb +22 -0
- data/adapters/hikki-memcache/lib/hikki/adapters/memcache_collection.rb +54 -0
- data/adapters/hikki-memcache/spec/hikki/adapters/memcache_adapter_integration_spec.rb +39 -0
- data/adapters/hikki-memcache/spec/hikki/adapters/memcache_adapter_spec.rb +115 -0
- data/adapters/hikki-memcache/spec/spec_helper.rb +8 -0
- data/adapters/hikki-mongo/.rspec +2 -0
- data/adapters/hikki-mongo/.travis.yml +3 -0
- data/adapters/hikki-mongo/Gemfile +7 -0
- data/adapters/hikki-mongo/LICENSE.txt +22 -0
- data/adapters/hikki-mongo/README.md +44 -0
- data/adapters/hikki-mongo/Rakefile +6 -0
- data/adapters/hikki-mongo/hikki-mongo.gemspec +28 -0
- data/adapters/hikki-mongo/lib/hikki/adapters/mongo_adapter.rb +22 -0
- data/adapters/hikki-mongo/lib/hikki/adapters/mongo_collection.rb +86 -0
- data/adapters/hikki-mongo/spec/hikki/adapters/mongo_adapter_integration_spec.rb +39 -0
- data/adapters/hikki-mongo/spec/hikki/adapters/mongo_adapter_spec.rb +231 -0
- data/adapters/hikki-mongo/spec/spec_helper.rb +8 -0
- data/adapters/hikki-redis/.rspec +2 -0
- data/adapters/hikki-redis/.travis.yml +3 -0
- data/adapters/hikki-redis/Gemfile +7 -0
- data/adapters/hikki-redis/LICENSE.txt +22 -0
- data/adapters/hikki-redis/README.md +44 -0
- data/adapters/hikki-redis/Rakefile +6 -0
- data/adapters/hikki-redis/hikki-redis.gemspec +27 -0
- data/adapters/hikki-redis/lib/hikki/adapters/redis_adapter.rb +21 -0
- data/adapters/hikki-redis/lib/hikki/adapters/redis_collection.rb +105 -0
- data/adapters/hikki-redis/spec/hikki/adapters/redis_adapter_integration_spec.rb +39 -0
- data/adapters/hikki-redis/spec/hikki/adapters/redis_adapter_spec.rb +258 -0
- data/adapters/hikki-redis/spec/spec_helper.rb +8 -0
- data/all_specs +13 -0
- data/hikki.gemspec +24 -0
- data/lib/hikki.rb +9 -0
- data/lib/hikki/adapters/adapter.rb +43 -0
- data/lib/hikki/adapters/memory_adapter.rb +18 -0
- data/lib/hikki/adapters/memory_collection.rb +87 -0
- data/lib/hikki/collection.rb +62 -0
- data/lib/hikki/repository.rb +54 -0
- data/lib/hikki/version.rb +3 -0
- data/spec/hikki/adapters/memory_adapter_spec.rb +242 -0
- data/spec/hikki/repository_spec.rb +260 -0
- data/spec/hikki_spec.rb +5 -0
- data/spec/spec_helper.rb +2 -0
- metadata +146 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'hikki/adapters/memcache_adapter'
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
5
|
+
config.run_all_when_everything_filtered = true
|
6
|
+
config.filter_run :focus
|
7
|
+
config.filter_run_excluding :integration
|
8
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 alexpeachey
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Hikki::Adapters::MongoAdapter
|
2
|
+
|
3
|
+
A Mongo adapter for Hikki.
|
4
|
+
It uses the `mongo` gem to communicate with Mongo.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'hikki-mongo'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install hikki-mongo
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
By default, the adapter will use `Mongo::MongoClient.new` as it's connection which uses the defaults in that gem.
|
23
|
+
You can pass in your own connection to use instead, useful for specifying a server and other options.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Use the default connection
|
27
|
+
adapter = Hikki::Adapters::MongoAdapter.new
|
28
|
+
|
29
|
+
# Use a specific connection
|
30
|
+
mongo = Mongo::MongoClient.new("db.example.com", 27017)
|
31
|
+
adapter = Hikki::Adapters::MongoAdapter.new(mongo)
|
32
|
+
```
|
33
|
+
|
34
|
+
If you do not specify an `id` when saving, the adapter will generate a `BSON::ObjectId`.
|
35
|
+
|
36
|
+
## Contributing
|
37
|
+
|
38
|
+
1. Fork it ( http://github.com/originate/hikki/fork )
|
39
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
40
|
+
3. Write your specifications
|
41
|
+
4. Implement your specifications
|
42
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
43
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
44
|
+
7. Create new Pull Request
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.expand_path('../../../lib/hikki/version', __FILE__)
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'hikki-mongo'
|
8
|
+
spec.version = Hikki::VERSION
|
9
|
+
spec.authors = ['alexpeachey']
|
10
|
+
spec.email = ['alex.peachey@originate.com']
|
11
|
+
spec.summary = 'A Mongo adapter for Hikki.'
|
12
|
+
spec.description = 'A Mongo adapter for Hikki.'
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
#spec.add_dependency 'hikki', Hikki::VERSION
|
22
|
+
spec.add_dependency 'mongo'
|
23
|
+
spec.add_dependency 'bson_ext'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'rspec'
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
require 'hikki'
|
3
|
+
require_relative './mongo_collection'
|
4
|
+
|
5
|
+
module Hikki
|
6
|
+
module Adapters
|
7
|
+
class MongoAdapter < Hikki::Adapters::Adapter
|
8
|
+
attr_reader :connection, :db, :uuid_generator
|
9
|
+
|
10
|
+
def initialize(connection=Mongo::MongoClient.new, db=connection['hikki'], uuid_generator=BSON::ObjectId)
|
11
|
+
super()
|
12
|
+
@connection = connection
|
13
|
+
@db = db
|
14
|
+
@uuid_generator = uuid_generator
|
15
|
+
end
|
16
|
+
|
17
|
+
def collection_for(collection)
|
18
|
+
collections.fetch(collection, MongoCollection.new(collection, connection, db, uuid_generator))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Hikki
|
2
|
+
module Adapters
|
3
|
+
class MongoCollection < Hikki::Collection
|
4
|
+
attr_reader :connection, :db, :uuid_generator
|
5
|
+
|
6
|
+
def initialize(collection, connection, db, uuid_generator)
|
7
|
+
super(collection)
|
8
|
+
@connection = connection
|
9
|
+
@db = db
|
10
|
+
@uuid_generator = uuid_generator
|
11
|
+
end
|
12
|
+
|
13
|
+
def index(field)
|
14
|
+
db[collection].create_index(field.to_s)
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def save(data)
|
19
|
+
data = normalize_data(data)
|
20
|
+
db[collection].update({ '_id' => data['_id'] }, data, { upsert: true })
|
21
|
+
data['_id'] = data['_id'].to_s
|
22
|
+
data
|
23
|
+
end
|
24
|
+
|
25
|
+
def find(id)
|
26
|
+
stringify_ids(db[collection].find('_id' => bson(id)).to_a).first || {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def all(options={})
|
30
|
+
options = normalize_options(options)
|
31
|
+
stringify_ids(limit(offset(db[collection].find.sort({ '_id' => 1 }), options[:offset]), options[:limit]).to_a)
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_by(field, value, options={})
|
35
|
+
options = normalize_options(options)
|
36
|
+
stringify_ids(limit(offset(db[collection].find({ field.to_s => value }).sort({ '_id' => 1 }), options[:offset]), options[:limit]).to_a)
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove(id)
|
40
|
+
db[collection].remove({ '_id' => bson(id)})
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_all
|
45
|
+
db[collection].remove
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def stringify_ids(results)
|
50
|
+
results.each do |result|
|
51
|
+
result['_id'] = result['_id'].to_s if result.has_key? '_id'
|
52
|
+
end
|
53
|
+
results
|
54
|
+
end
|
55
|
+
|
56
|
+
def normalize_data(data)
|
57
|
+
deep_copy(data).tap do |d|
|
58
|
+
d.merge!('id' => id_for(d))
|
59
|
+
d.merge!('_id' => bson(d['id']))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def id_for(data)
|
64
|
+
data.fetch('id', data.fetch('_id', uuid_generator.new)).to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def bson(id)
|
69
|
+
uuid_generator.from_string(id.to_s)
|
70
|
+
rescue
|
71
|
+
id.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
def offset(cursor, offset)
|
75
|
+
return cursor unless offset > 0
|
76
|
+
cursor.skip(offset)
|
77
|
+
end
|
78
|
+
|
79
|
+
def limit(cursor, limit)
|
80
|
+
return cursor unless limit > 0
|
81
|
+
cursor.limit(limit)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Hikki
|
4
|
+
module Adapters
|
5
|
+
describe MongoAdapter, :integration do
|
6
|
+
context 'when actually using Mongo' do
|
7
|
+
subject(:adapter) { MongoAdapter.new }
|
8
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
9
|
+
let(:expected) { { 'id' => id, '_id' => id, 'field1' => 'test', 'field2' => 123 } }
|
10
|
+
let(:id) { '1' }
|
11
|
+
let(:collection) { 'collection1' }
|
12
|
+
|
13
|
+
it 'can store and retreive data' do
|
14
|
+
adapter.remove_all(collection)
|
15
|
+
adapter.index(collection, :field1)
|
16
|
+
adapter.save(collection, data)
|
17
|
+
expect(adapter.find(collection, id)).to eq expected
|
18
|
+
expect(adapter.find(collection, '2')).to eq Hash.new
|
19
|
+
expect(adapter.all(collection)).to eq [expected]
|
20
|
+
expect(adapter.find_by(collection, :field1, 'test')).to eq [expected]
|
21
|
+
expect(adapter.find_by(collection, :field2, 123)).to eq [expected]
|
22
|
+
expect(adapter.find_by(collection, :field1, 'foo')).to eq []
|
23
|
+
expect(adapter.find_by(collection, :field2, 1)).to eq []
|
24
|
+
adapter.remove(collection, id)
|
25
|
+
expect(adapter.find(collection, id)).to eq Hash.new
|
26
|
+
expect(adapter.all(collection)).to eq []
|
27
|
+
10.times do |i|
|
28
|
+
adapter.save(collection, { id: i, field1: "test-#{i%2}" })
|
29
|
+
end
|
30
|
+
expect(adapter.all(collection, {limit: 2, offset: 6})).to eq [{'id' => '6', '_id' => '6', 'field1' => 'test-0'}, {'id' => '7', '_id' => '7', 'field1' => 'test-1'}]
|
31
|
+
expect(adapter.find_by(collection, :field1, 'test-0', {limit: 2})).to eq [{'id' => '0', '_id' => '0', 'field1' => 'test-0'}, {'id' => '2', '_id' => '2', 'field1' => 'test-0'}]
|
32
|
+
adapter.remove_all(collection)
|
33
|
+
expect(adapter.find(collection, id)).to eq Hash.new
|
34
|
+
expect(adapter.all(collection)).to eq []
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Hikki
|
4
|
+
module Adapters
|
5
|
+
describe MongoAdapter do
|
6
|
+
subject(:adapter) { MongoAdapter.new(connection, db, uuid_generator) }
|
7
|
+
let(:connection) { double :connection }
|
8
|
+
let(:db) { double :db }
|
9
|
+
let(:mongo_collection) { double :mongo_collection, create_index: true, update: true, remove: true }
|
10
|
+
let(:uuid_generator) { double :uuid_generator, new: '12345' }
|
11
|
+
let(:collection) { 'collection1' }
|
12
|
+
before do
|
13
|
+
db.stub(:[]).with(collection).and_return(mongo_collection)
|
14
|
+
uuid_generator.stub(:from_string) { |arg| arg }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#index' do
|
18
|
+
it 'returns true' do
|
19
|
+
expect(adapter.index(collection, :field1)).to be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'adds an index to the collection' do
|
23
|
+
adapter.index(collection, :field1)
|
24
|
+
expect(mongo_collection).to have_received(:create_index).with('field1')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#save' do
|
29
|
+
context 'when an id is provided in the data' do
|
30
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
31
|
+
let(:expected) { { 'id' => id, '_id' => id, 'field1' => 'test', 'field2' => 123 } }
|
32
|
+
let(:id) { '1' }
|
33
|
+
|
34
|
+
it 'returns the data' do
|
35
|
+
expect(adapter.save(collection, data)).to eq expected
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'persists the data in the store' do
|
39
|
+
adapter.save(collection, data)
|
40
|
+
expect(mongo_collection).to have_received(:update).with({'_id' => '1'}, expected, { upsert: true })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when an id is not provided in the data' do
|
45
|
+
let(:data) { { field1: 'test', field2: 123 } }
|
46
|
+
let(:expected) { { 'id' => id, '_id' => id, 'field1' => 'test', 'field2' => 123 } }
|
47
|
+
let(:id) { '12345' }
|
48
|
+
|
49
|
+
it 'returns the data with the id added' do
|
50
|
+
expect(adapter.save(collection, data)).to eq expected
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'persists the data in the store' do
|
54
|
+
adapter.save(collection, data)
|
55
|
+
expect(mongo_collection).to have_received(:update).with({'_id' => '12345'}, expected, { upsert: true })
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#find' do
|
61
|
+
let(:id) { '1' }
|
62
|
+
|
63
|
+
context 'when the id exists' do
|
64
|
+
let(:found) { { 'id' => id, '_id' => 1, 'field1' => 'test', 'field2' => 123 } }
|
65
|
+
let(:expected) { { 'id' => id, '_id' => '1', 'field1' => 'test', 'field2' => 123 } }
|
66
|
+
before { mongo_collection.stub(:find).with({ '_id' => id }).and_return([found]) }
|
67
|
+
|
68
|
+
it 'retrieves the data' do
|
69
|
+
expect(adapter.find(collection, id)).to eq expected
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when the id does not exist' do
|
74
|
+
let(:expected) { {} }
|
75
|
+
before { mongo_collection.stub(:find).with({ '_id' => id }).and_return([]) }
|
76
|
+
|
77
|
+
it 'returns an empty hash' do
|
78
|
+
expect(adapter.find(collection, id)).to eq expected
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#all' do
|
84
|
+
context 'with a record in the collection' do
|
85
|
+
let(:data) { { id: '1', field1: 'test', field2: 123 } }
|
86
|
+
let(:found) { { 'id' => '1', '_id' => 1, 'field1' => 'test', 'field2' => 123 } }
|
87
|
+
let(:expected) { { 'id' => '1', '_id' => '1', 'field1' => 'test', 'field2' => 123 } }
|
88
|
+
let(:cursor) { double :cursor }
|
89
|
+
before do
|
90
|
+
mongo_collection.stub(:find).and_return(cursor)
|
91
|
+
cursor.stub(:sort).with({ '_id' => 1 }).and_return([found])
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'returns an array containing the record' do
|
95
|
+
expect(adapter.all(collection)).to eq [expected]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'with no records in the collection' do
|
100
|
+
let(:cursor) { double :cursor }
|
101
|
+
before do
|
102
|
+
mongo_collection.stub(:find).and_return(cursor)
|
103
|
+
cursor.stub(:sort).with({ '_id' => 1 }).and_return([])
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'returns an array containing the record' do
|
107
|
+
expect(adapter.all(collection)).to eq []
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'with multiple records and paging options specified' do
|
112
|
+
let(:cursor) { double :cursor, limit: nil, skip: nil, sort: nil }
|
113
|
+
|
114
|
+
before do
|
115
|
+
mongo_collection.stub(:find).and_return(cursor)
|
116
|
+
cursor.stub(:sort).and_return(cursor)
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'with limit 2' do
|
120
|
+
let(:found) { [{'id' => '1', '_id' => 1, 'a' => 1 }, {'id' => '2', '_id' => 2, 'a' => 1 }] }
|
121
|
+
let(:expected) { [{'id' => '1', '_id' => '1', 'a' => 1 }, {'id' => '2', '_id' => '2', 'a' => 1 }] }
|
122
|
+
before { cursor.stub(:limit).and_return(found) }
|
123
|
+
|
124
|
+
it 'returns the first 2 records' do
|
125
|
+
expect(adapter.all(collection, {limit: 2})).to eq expected
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'with an offset of 4' do
|
129
|
+
let(:found) { [{'id' => '5', '_id' => 5, 'a' => 1 }, {'id' => '6', '_id' => 6, 'a' => 1 }] }
|
130
|
+
let(:expected) { [{'id' => '5', '_id' => '5', 'a' => 1 }, {'id' => '6', '_id' => '6', 'a' => 1 }] }
|
131
|
+
let(:skip_cursor) { double :skip_cursor, limit: nil }
|
132
|
+
before do
|
133
|
+
cursor.stub(:skip).with(4).and_return(skip_cursor)
|
134
|
+
skip_cursor.stub(:limit).with(2).and_return(found)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'returns the 2 records starting with the offset' do
|
138
|
+
expect(adapter.all(collection, {limit: 2, offset: 4})).to eq expected
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe '#find_by' do
|
146
|
+
context 'with a record in the collection' do
|
147
|
+
let(:data) { { id: '1', field1: 'test', field2: 123 } }
|
148
|
+
let(:found) { { 'id' => '1', '_id' => 1, 'field1' => 'test', 'field2' => 123 } }
|
149
|
+
let(:expected) { { 'id' => '1', '_id' => '1', 'field1' => 'test', 'field2' => 123 } }
|
150
|
+
let(:cursor) { double :cursor }
|
151
|
+
before do
|
152
|
+
mongo_collection.stub(:find).with({ 'field1' => 'test' }).and_return(cursor)
|
153
|
+
cursor.stub(:sort).with({ '_id' => 1 }).and_return([found])
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'returns an array containing the record' do
|
157
|
+
expect(adapter.find_by(collection, :field1, 'test')).to eq [expected]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'with no records in the collection' do
|
162
|
+
let(:cursor) { double :cursor }
|
163
|
+
before do
|
164
|
+
mongo_collection.stub(:find).with({ 'field1' => 'test' }).and_return(cursor)
|
165
|
+
cursor.stub(:sort).with({ '_id' => 1 }).and_return([])
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'returns an array containing the record' do
|
169
|
+
expect(adapter.find_by(collection, :field1, 'test')).to eq []
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'with multiple records and paging options specified' do
|
174
|
+
let(:cursor) { double :cursor, limit: nil, skip: nil, sort: nil }
|
175
|
+
|
176
|
+
before do
|
177
|
+
mongo_collection.stub(:find).with({ 'a' => 1 }).and_return(cursor)
|
178
|
+
cursor.stub(:sort).and_return(cursor)
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'with limit 2' do
|
182
|
+
let(:found) { [{'id' => '1', '_id' => 1, 'a' => 1 }, {'id' => '2', '_id' => 2, 'a' => 1 }] }
|
183
|
+
let(:expected) { [{'id' => '1', '_id' => '1', 'a' => 1 }, {'id' => '2', '_id' => '2', 'a' => 1 }] }
|
184
|
+
before { cursor.stub(:limit).and_return(found) }
|
185
|
+
|
186
|
+
it 'returns the first 2 records' do
|
187
|
+
expect(adapter.find_by(collection, :a, 1, {limit: 2})).to eq expected
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'with an offset of 4' do
|
191
|
+
let(:found) { [{'id' => '5', '_id' => 5, 'a' => 1 }, {'id' => '6', '_id' => 6, 'a' => 1 }] }
|
192
|
+
let(:expected) { [{'id' => '5', '_id' => '5', 'a' => 1 }, {'id' => '6', '_id' => '6', 'a' => 1 }] }
|
193
|
+
let(:skip_cursor) { double :skip_cursor, limit: nil }
|
194
|
+
before do
|
195
|
+
cursor.stub(:skip).with(4).and_return(skip_cursor)
|
196
|
+
skip_cursor.stub(:limit).with(2).and_return(found)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'returns the 2 records starting with the offset' do
|
200
|
+
expect(adapter.find_by(collection, :a, 1, {limit: 2, offset: 4})).to eq expected
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe '#remove' do
|
208
|
+
it 'returns true' do
|
209
|
+
expect(adapter.remove(collection, '1')).to be_true
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'removes the record from the store' do
|
213
|
+
adapter.remove(collection, '1')
|
214
|
+
expect(mongo_collection).to have_received(:remove).with({'_id' => '1'})
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#remove_all' do
|
219
|
+
it 'returns true' do
|
220
|
+
expect(adapter.remove_all(collection)).to be_true
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'removes all of the records from the store' do
|
224
|
+
adapter.remove_all(collection)
|
225
|
+
expect(mongo_collection).to have_received(:remove).with()
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|