hikki-redis 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/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/hikki-redis.gemspec +27 -0
- data/lib/hikki/adapters/redis_adapter.rb +21 -0
- data/lib/hikki/adapters/redis_collection.rb +105 -0
- data/spec/hikki/adapters/redis_adapter_integration_spec.rb +39 -0
- data/spec/hikki/adapters/redis_adapter_spec.rb +258 -0
- data/spec/spec_helper.rb +8 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 54541993c901f1077ce9f3f1e679da5e3e6266aa
|
4
|
+
data.tar.gz: bb7df13fdb257d939843f56927c864d6009020e4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 322f97c3154c812d9f16c5a09ddc949b4be10b758e49fa172b7841bd63525d7291acec02e96596c40bc90c7607a295a7b8fe2113c021eab805064a0a47aaa929
|
7
|
+
data.tar.gz: 31b501644b28b6952ae5318d9199111e296d07ca840b7549f927b031f923195a6d7df992e6be4bd83f66911c69c1ce48b4a4cd90bd074507ea814e76d32a6a1d
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Hikki::Adapters::RedisAdapter
|
2
|
+
|
3
|
+
A Redis adapter for Hikki.
|
4
|
+
It uses the `redis` gem to communicate with Redis.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'hikki-redis'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install hikki-redis
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
By default, the adapter will use `Redis.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::RedisAdapter.new
|
28
|
+
|
29
|
+
# Use a specific connection
|
30
|
+
redis = Redis.new(:url => "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
31
|
+
adapter = Hikki::Adapters::RedisAdapter.new(redis)
|
32
|
+
```
|
33
|
+
|
34
|
+
If you do not specify an `id` when saving, the adapter will generate a uuid using `SecureRandom`.
|
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
|
data/Rakefile
ADDED
data/hikki-redis.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
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-redis'
|
8
|
+
spec.version = Hikki::VERSION
|
9
|
+
spec.authors = ['alexpeachey']
|
10
|
+
spec.email = ['alex.peachey@originate.com']
|
11
|
+
spec.summary = 'A Redis adapter for Hikki.'
|
12
|
+
spec.description = 'A Redis 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 'redis'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rspec'
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'hikki'
|
3
|
+
require_relative './redis_collection'
|
4
|
+
|
5
|
+
module Hikki
|
6
|
+
module Adapters
|
7
|
+
class RedisAdapter < Hikki::Adapters::Adapter
|
8
|
+
attr_reader :connection, :uuid_generator
|
9
|
+
|
10
|
+
def initialize(connection=Redis.new, uuid_generator=SecureRandom)
|
11
|
+
super()
|
12
|
+
@connection = connection
|
13
|
+
@uuid_generator = uuid_generator
|
14
|
+
end
|
15
|
+
|
16
|
+
def collection_for(collection)
|
17
|
+
collections.fetch(collection, RedisCollection.new(collection, connection, uuid_generator))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Hikki
|
2
|
+
module Adapters
|
3
|
+
class RedisCollection < Hikki::Collection
|
4
|
+
attr_reader :connection, :uuid_generator
|
5
|
+
|
6
|
+
def initialize(collection, connection, uuid_generator)
|
7
|
+
super(collection)
|
8
|
+
@connection = connection
|
9
|
+
@uuid_generator = uuid_generator
|
10
|
+
end
|
11
|
+
|
12
|
+
def index(field)
|
13
|
+
connection.sadd collection_indexes_key, field.to_s
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def save(data)
|
18
|
+
data = normalize_data(data)
|
19
|
+
connection.hset collection_key, data['id'], data.to_json
|
20
|
+
add_to_index(data)
|
21
|
+
data
|
22
|
+
end
|
23
|
+
|
24
|
+
def find(id)
|
25
|
+
JSON.parse(connection.hget(collection_key, id.to_s) || '{}')
|
26
|
+
end
|
27
|
+
|
28
|
+
def all(options={})
|
29
|
+
options = normalize_options(options)
|
30
|
+
connection.hvals(collection_key)[page_range(options)].map { |j| JSON.parse(j) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_by(field, value, options={})
|
34
|
+
options = normalize_options(options)
|
35
|
+
return find_by_index(field, value, options) if has_index?(field)
|
36
|
+
all.select { |o| o.fetch(field.to_s) == value }[page_range(options)]
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove(id)
|
40
|
+
remove_from_index(find(id))
|
41
|
+
connection.hdel collection_key, id.to_s
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove_all
|
46
|
+
indexes.each { |field| connection.del collection_index_key(field) }
|
47
|
+
connection.del collection_indexes_key
|
48
|
+
connection.del collection_key
|
49
|
+
end
|
50
|
+
|
51
|
+
def has_index?(field)
|
52
|
+
connection.sismember collection_indexes_key, field.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def indexes
|
56
|
+
connection.smembers collection_indexes_key
|
57
|
+
end
|
58
|
+
|
59
|
+
def id_for(data)
|
60
|
+
data.fetch('id', uuid_generator.uuid).to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def collection_indexes_key
|
65
|
+
"hikki:#{collection}:indexes"
|
66
|
+
end
|
67
|
+
|
68
|
+
def collection_index_key(field)
|
69
|
+
"hikki:#{collection}:#{field.to_s}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def collection_key
|
73
|
+
"hikki:#{collection}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_to_index(data)
|
77
|
+
indexes.each do |field|
|
78
|
+
existing = indexed_ids(field, data[field])
|
79
|
+
existing << data['id'] unless existing.include? data['id']
|
80
|
+
connection.hset collection_index_key(field), data[field], existing.to_json
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def remove_from_index(data)
|
85
|
+
return if data == {}
|
86
|
+
indexes.each do |field|
|
87
|
+
ids = indexed_ids(field, data[field])
|
88
|
+
ids.delete(data['id'])
|
89
|
+
connection.hset collection_index_key(field), data[field].to_s, ids.to_json
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def indexed_ids(field, value)
|
94
|
+
JSON.parse(connection.hget(collection_index_key(field), value.to_s) || '[]')
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_by_index(field, value, options)
|
98
|
+
ids = indexed_ids(field, value)
|
99
|
+
results = connection.pipelined { ids.each { |id| connection.hget collection_key, id } }
|
100
|
+
results.map { |j| JSON.parse(j) }.reject { |v| v == {} }[page_range(options)]
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Hikki
|
4
|
+
module Adapters
|
5
|
+
describe RedisAdapter, :integration do
|
6
|
+
context 'when actually using Redis' do
|
7
|
+
subject(:adapter) { RedisAdapter.new }
|
8
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
9
|
+
let(:expected) { { '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', 'field1' => 'test-0'}, {'id' => '7', 'field1' => 'test-1'}]
|
31
|
+
expect(adapter.find_by(collection, :field1, 'test-0', {limit: 2})).to eq [{'id' => '0', 'field1' => 'test-0'}, {'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,258 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Hikki
|
4
|
+
module Adapters
|
5
|
+
describe RedisAdapter do
|
6
|
+
subject(:adapter) { RedisAdapter.new(connection, uuid_generator) }
|
7
|
+
let(:connection) { double :connection, sadd: true, smembers: [], hset: true, hget: true, hdel: true, del: true }
|
8
|
+
let(:uuid_generator) { double :uuid_generator, uuid: '12345' }
|
9
|
+
let(:collection) { 'collection1' }
|
10
|
+
|
11
|
+
describe '#index' do
|
12
|
+
it 'returns true' do
|
13
|
+
expect(adapter.index(collection, :field1)).to be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'adds the field to the index list' do
|
17
|
+
adapter.index(collection, :field1)
|
18
|
+
expect(connection).to have_received(:sadd).with('hikki:collection1:indexes', 'field1')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#save' do
|
23
|
+
context 'when an id is provided in the data' do
|
24
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
25
|
+
let(:expected) { { 'id' => id, 'field1' => 'test', 'field2' => 123 } }
|
26
|
+
let(:json) { '{"id":"1","field1":"test","field2":123}' }
|
27
|
+
let(:id) { '1' }
|
28
|
+
|
29
|
+
it 'returns the data' do
|
30
|
+
expect(adapter.save(collection, data)).to eq expected
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'persists the data in the store' do
|
34
|
+
adapter.save(collection, data)
|
35
|
+
expect(connection).to have_received(:hset).with('hikki:collection1', id, json)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when an id is not provided in the data' do
|
40
|
+
let(:data) { { field1: 'test', field2: 123 } }
|
41
|
+
let(:expected) { { 'id' => id, 'field1' => 'test', 'field2' => 123 } }
|
42
|
+
let(:json) { '{"field1":"test","field2":123,"id":"12345"}' }
|
43
|
+
let(:id) { '12345' }
|
44
|
+
|
45
|
+
it 'returns the data with the id added' do
|
46
|
+
expect(adapter.save(collection, data)).to eq expected
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'persists the data in the store' do
|
50
|
+
adapter.save(collection, data)
|
51
|
+
expect(connection).to have_received(:hset).with('hikki:collection1', id, json)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when an index exists on a field in the data' do
|
56
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
57
|
+
let(:json) { '{"id":"1","field1":"test","field2":123}' }
|
58
|
+
let(:id) { '1' }
|
59
|
+
before do
|
60
|
+
connection.stub(:smembers).with('hikki:collection1:indexes').and_return(['field1'])
|
61
|
+
connection.stub(:hget).with('hikki:collection1:field1', 'test').and_return('[]')
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'adds an entry in the index' do
|
65
|
+
expect(connection).to receive(:hset).with('hikki:collection1', id, json)
|
66
|
+
expect(connection).to receive(:hset).with('hikki:collection1:field1', 'test', '["1"]')
|
67
|
+
adapter.save(collection, data)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#find' do
|
73
|
+
let(:id) { '1' }
|
74
|
+
|
75
|
+
context 'when the id exists' do
|
76
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
77
|
+
let(:json) { '{"id":"1","field1":"test","field2":123}' }
|
78
|
+
let(:expected) { { 'id' => id, 'field1' => 'test', 'field2' => 123 } }
|
79
|
+
before { connection.stub(:hget).with('hikki:collection1', id).and_return(json) }
|
80
|
+
|
81
|
+
it 'retrieves the data' do
|
82
|
+
expect(adapter.find(collection, id)).to eq expected
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when the id does not exist' do
|
87
|
+
let(:expected) { {} }
|
88
|
+
before { connection.stub(:hget).with('hikki:collection1', id).and_return(nil) }
|
89
|
+
|
90
|
+
it 'returns an empty hash' do
|
91
|
+
expect(adapter.find(collection, id)).to eq expected
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#all' do
|
97
|
+
context 'with a record in the collection' do
|
98
|
+
let(:data) { { id: '1', field1: 'test', field2: 123 } }
|
99
|
+
let(:json) { '{"id":"1","field1":"test","field2":123}' }
|
100
|
+
let(:expected) { { 'id' => '1', 'field1' => 'test', 'field2' => 123 } }
|
101
|
+
before { connection.stub(:hvals).with('hikki:collection1').and_return([json]) }
|
102
|
+
|
103
|
+
it 'returns an array containing the record' do
|
104
|
+
expect(adapter.all(collection)).to eq [expected]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'with no records in the collection' do
|
109
|
+
before { connection.stub(:hvals).with('hikki:collection1').and_return([]) }
|
110
|
+
|
111
|
+
it 'returns an array containing the record' do
|
112
|
+
expect(adapter.all(collection)).to eq []
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'with multiple records and paging options specified' do
|
117
|
+
before do
|
118
|
+
results = (1..10).map {|i| "{\"id\":\"#{i}\",\"a\":1}" }
|
119
|
+
connection.stub(:hvals).with('hikki:collection1').and_return(results)
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'with limit 2' do
|
123
|
+
let(:limit) { 2 }
|
124
|
+
|
125
|
+
it 'returns only 2 records' do
|
126
|
+
expect(adapter.all(collection, {limit: 2}).count).to eq 2
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'with an offset of 4' do
|
130
|
+
it 'returns the 2 records starting with the offset' do
|
131
|
+
expect(adapter.all(collection, {limit: 2, offset: 4})).to eq [{'id' => '5', 'a' => 1}, {'id' => '6', 'a' => 1}]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '#find_by' do
|
139
|
+
context 'with a record in the collection matching' do
|
140
|
+
let(:data) { { id: id, field1: 'test', field2: 123 } }
|
141
|
+
let(:json) { '{"id":"1","field1":"test","field2":123}' }
|
142
|
+
let(:expected) { { 'id' => id, 'field1' => 'test', 'field2' => 123 } }
|
143
|
+
let(:id) { '1' }
|
144
|
+
|
145
|
+
context 'without an index' do
|
146
|
+
before do
|
147
|
+
connection.stub(:sismember).with('hikki:collection1:indexes', 'field2').and_return(false)
|
148
|
+
connection.stub(:hvals).with('hikki:collection1').and_return([json])
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'returns an array containing the record' do
|
152
|
+
expect(adapter.find_by(collection, :field2, 123)).to eq [expected]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'with an index' do
|
157
|
+
before do
|
158
|
+
connection.stub(:sismember).with('hikki:collection1:indexes', 'field1').and_return(true)
|
159
|
+
connection.stub(:hget).with('hikki:collection1:field1', 'test').and_return('[1]')
|
160
|
+
connection.stub(:hget).with('hikki:collection1', id).and_return(json)
|
161
|
+
connection.stub(:pipelined).and_yield.and_return([json])
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'returns an array containing the record' do
|
165
|
+
expect(adapter.find_by(collection, :field1, 'test')).to eq [expected]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'with no matching records in the collection' do
|
171
|
+
before do
|
172
|
+
connection.stub(:sismember).with('hikki:collection1:indexes', 'field1').and_return(false)
|
173
|
+
connection.stub(:hvals).with('hikki:collection1').and_return([])
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'returns an empty array' do
|
177
|
+
expect(adapter.find_by(collection, :field1, 'foo')).to eq []
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'with multiple matching records and paging options specified' do
|
182
|
+
before do
|
183
|
+
results = (1..10).map {|i| "{\"id\":\"#{i}\",\"a\":1}" }
|
184
|
+
connection.stub(:sismember).with('hikki:collection1:indexes', 'a').and_return(false)
|
185
|
+
connection.stub(:hvals).with('hikki:collection1').and_return(results)
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'with limit 2' do
|
189
|
+
let(:limit) { 2 }
|
190
|
+
|
191
|
+
it 'returns only 2 records' do
|
192
|
+
expect(adapter.find_by(collection, :a, 1, {limit: 2}).count).to eq 2
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'with an offset of 4' do
|
196
|
+
it 'returns the 2 records starting with the offset' do
|
197
|
+
expect(adapter.find_by(collection, :a, 1, {limit: 2, offset: 4})).to eq [{'id' => '5', 'a' => 1}, {'id' => '6', 'a' => 1}]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#remove' do
|
205
|
+
context 'with a record for the id in the collection' do
|
206
|
+
let(:id) { '1' }
|
207
|
+
let(:json) { '{"id":"1","field1":"test","field2":123}' }
|
208
|
+
before { connection.stub(:hget).with('hikki:collection1', id).and_return(json) }
|
209
|
+
|
210
|
+
it 'returns true' do
|
211
|
+
expect(adapter.remove(collection, id)).to be_true
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'removes the record from the store' do
|
215
|
+
adapter.remove(collection, id)
|
216
|
+
expect(connection).to have_received(:hdel).with('hikki:collection1', id)
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'when there is an index' do
|
220
|
+
before do
|
221
|
+
connection.stub(:smembers).with('hikki:collection1:indexes').and_return(['field1'])
|
222
|
+
connection.stub(:hget).with('hikki:collection1:field1', 'test').and_return('["1"]')
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'removes the id from the index' do
|
226
|
+
adapter.remove(collection, id)
|
227
|
+
expect(connection).to have_received(:hset).with('hikki:collection1:field1', 'test', '[]')
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe '#remove_all' do
|
234
|
+
context 'with a record in the collection' do
|
235
|
+
it 'returns true' do
|
236
|
+
expect(adapter.remove_all(collection)).to be_true
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'removes all records from the store' do
|
240
|
+
expect(connection).to receive(:del).with('hikki:collection1:indexes')
|
241
|
+
expect(connection).to receive(:del).with('hikki:collection1')
|
242
|
+
adapter.remove_all(collection)
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'when there is an index' do
|
246
|
+
before { connection.stub(:smembers).with('hikki:collection1:indexes').and_return(['field1']) }
|
247
|
+
|
248
|
+
it 'removes the indexes' do
|
249
|
+
adapter.remove_all(collection)
|
250
|
+
expect(connection).to have_received(:del).with('hikki:collection1:field1')
|
251
|
+
expect(connection).to have_received(:del).with('hikki:collection1:indexes')
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'hikki/adapters/redis_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
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hikki-redis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- alexpeachey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hikki
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: A Redis adapter for Hikki.
|
84
|
+
email:
|
85
|
+
- alex.peachey@originate.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- .rspec
|
91
|
+
- .travis.yml
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- hikki-redis.gemspec
|
97
|
+
- lib/hikki/adapters/redis_adapter.rb
|
98
|
+
- lib/hikki/adapters/redis_collection.rb
|
99
|
+
- spec/hikki/adapters/redis_adapter_integration_spec.rb
|
100
|
+
- spec/hikki/adapters/redis_adapter_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
homepage: ''
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubyforge_project:
|
122
|
+
rubygems_version: 2.2.1
|
123
|
+
signing_key:
|
124
|
+
specification_version: 4
|
125
|
+
summary: A Redis adapter for Hikki.
|
126
|
+
test_files:
|
127
|
+
- spec/hikki/adapters/redis_adapter_integration_spec.rb
|
128
|
+
- spec/hikki/adapters/redis_adapter_spec.rb
|
129
|
+
- spec/spec_helper.rb
|