flipper-mongo 0.1.1 → 0.2.0
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/flipper-mongo.gemspec +1 -1
- data/lib/flipper/adapters/mongo.rb +21 -30
- data/lib/flipper/adapters/mongo/document.rb +77 -0
- data/lib/flipper/adapters/mongo/version.rb +1 -1
- data/lib/flipper/adapters/mongo_single_document.rb +25 -0
- data/spec/flipper/adapters/mongo/document_spec.rb +275 -0
- data/spec/flipper/adapters/mongo_single_document_spec.rb +39 -0
- data/spec/flipper/adapters/mongo_spec.rb +8 -8
- metadata +13 -10
- data/lib/flipper/adapters/mongo_with_ttl.rb +0 -36
- data/spec/flipper/adapters/mongo_with_ttl_spec.rb +0 -44
data/flipper-mongo.gemspec
CHANGED
@@ -1,64 +1,55 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'forwardable'
|
2
3
|
require 'mongo'
|
3
4
|
|
4
5
|
module Flipper
|
5
6
|
module Adapters
|
6
7
|
class Mongo
|
7
|
-
|
8
|
+
extend Forwardable
|
8
9
|
|
9
|
-
def initialize(collection
|
10
|
+
def initialize(collection)
|
10
11
|
@collection = collection
|
11
|
-
@
|
12
|
-
@mongo_criteria = {:_id => id}
|
13
|
-
@mongo_options = {:upsert => true, :safe => true}
|
12
|
+
@update_options = {:safe => true, :upsert => true}
|
14
13
|
end
|
15
14
|
|
16
15
|
def read(key)
|
17
|
-
|
16
|
+
find_one key
|
18
17
|
end
|
19
18
|
|
20
19
|
def write(key, value)
|
21
|
-
update '$set' => {
|
20
|
+
update key, {'$set' => {'v' => value}}
|
22
21
|
end
|
23
22
|
|
24
23
|
def delete(key)
|
25
|
-
|
24
|
+
@collection.remove criteria(key)
|
26
25
|
end
|
27
26
|
|
28
|
-
def
|
29
|
-
|
27
|
+
def set_members(key)
|
28
|
+
(find_one(key) || Set.new).to_set
|
30
29
|
end
|
31
30
|
|
32
|
-
def
|
33
|
-
update '$
|
31
|
+
def set_add(key, value)
|
32
|
+
update key, {'$addToSet' => {'v' => value}}
|
34
33
|
end
|
35
34
|
|
36
|
-
def
|
37
|
-
|
35
|
+
def set_delete(key, value)
|
36
|
+
update key, {'$pull' => {'v' => value}}
|
38
37
|
end
|
39
38
|
|
40
39
|
private
|
41
40
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def update(updates)
|
47
|
-
@collection.update(@mongo_criteria, updates, @mongo_options)
|
41
|
+
def find_one(key)
|
42
|
+
if (doc = @collection.find_one(criteria(key)))
|
43
|
+
doc['v']
|
44
|
+
end
|
48
45
|
end
|
49
46
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
if block_given?
|
54
|
-
@document.fetch(key, &block)
|
55
|
-
else
|
56
|
-
@document[key]
|
57
|
-
end
|
47
|
+
def update(key, updates)
|
48
|
+
@collection.update criteria(key), updates, @update_options
|
58
49
|
end
|
59
50
|
|
60
|
-
def
|
61
|
-
|
51
|
+
def criteria(key)
|
52
|
+
{:_id => key}
|
62
53
|
end
|
63
54
|
end
|
64
55
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'mongo'
|
3
|
+
|
4
|
+
module Flipper
|
5
|
+
module Adapters
|
6
|
+
class MongoSingleDocument
|
7
|
+
class Document
|
8
|
+
DefaultId = 'flipper'
|
9
|
+
|
10
|
+
def initialize(collection, options = {})
|
11
|
+
@collection = collection
|
12
|
+
@options = options
|
13
|
+
@id = @options.fetch(:id) { DefaultId }
|
14
|
+
@source = @options.fetch(:source) { {} }
|
15
|
+
@criteria = {:_id => @id}
|
16
|
+
@mongo_options = {:safe => true, :upsert => true}
|
17
|
+
end
|
18
|
+
|
19
|
+
def read(key)
|
20
|
+
source[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def write(key, value)
|
24
|
+
@collection.update @criteria, {'$set' => {key => value}}, @mongo_options
|
25
|
+
@source[key] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(key)
|
29
|
+
@collection.update @criteria, {'$unset' => {key => 1}}, @mongo_options
|
30
|
+
@source.delete key
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_members(key)
|
34
|
+
members = source.fetch(key) { @source[key] = Set.new }
|
35
|
+
|
36
|
+
if members.is_a?(Array)
|
37
|
+
@source[key] = members.to_set
|
38
|
+
else
|
39
|
+
members
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_add(key, value)
|
44
|
+
@collection.update @criteria, {'$addToSet' => {key => value}}, @mongo_options
|
45
|
+
set_members(key).add(value)
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_delete(key, value)
|
49
|
+
@collection.update @criteria, {'$pull' => {key => value}}, @mongo_options
|
50
|
+
set_members(key).delete(value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def clear
|
54
|
+
@loaded = nil
|
55
|
+
@source.clear
|
56
|
+
end
|
57
|
+
|
58
|
+
def loaded?
|
59
|
+
@loaded == true
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def source
|
65
|
+
load unless loaded?
|
66
|
+
@source
|
67
|
+
end
|
68
|
+
|
69
|
+
def load
|
70
|
+
@loaded = true
|
71
|
+
@source.clear
|
72
|
+
@source.update @collection.find_one(@criteria) || {}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'mongo'
|
4
|
+
require 'flipper/adapters/mongo/document'
|
5
|
+
|
6
|
+
module Flipper
|
7
|
+
module Adapters
|
8
|
+
class MongoSingleDocument
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def initialize(collection, options = {})
|
12
|
+
@collection = collection
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def_delegators :document, :read, :write, :delete, :set_members, :set_add, :set_delete
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def document
|
21
|
+
Document.new(@collection, :id => @options[:id])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'flipper/adapters/mongo/document'
|
3
|
+
|
4
|
+
describe Flipper::Adapters::MongoSingleDocument::Document do
|
5
|
+
subject { described_class.new(collection, :id => id, :source => source) }
|
6
|
+
let(:collection) { Mongo::Connection.new.db('testing')['testing'] }
|
7
|
+
let(:id) { described_class::DefaultId }
|
8
|
+
let(:source) { {} }
|
9
|
+
let(:criteria) { {:_id => id} }
|
10
|
+
let(:options) { {:safe => true, :upsert => true} }
|
11
|
+
|
12
|
+
def document
|
13
|
+
collection.find_one(criteria)
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
collection.remove(criteria)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "defaults id to flipper" do
|
21
|
+
described_class.new(collection).instance_variable_get("@id").should eq('flipper')
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "loading document" do
|
25
|
+
before do
|
26
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar', 'people' => [1, 2, 3]}}, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "only happens once" do
|
30
|
+
collection.should_receive(:find_one).with(criteria).once.and_return({})
|
31
|
+
subject.read('foo')
|
32
|
+
subject.set_members('people')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "happens again if document is cleared" do
|
36
|
+
collection.should_receive(:find_one).with(criteria)
|
37
|
+
subject.read('foo')
|
38
|
+
subject.set_members('people')
|
39
|
+
|
40
|
+
subject.clear
|
41
|
+
|
42
|
+
collection.should_receive(:find_one).with(criteria)
|
43
|
+
subject.read('foo')
|
44
|
+
subject.set_members('people')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#read" do
|
49
|
+
context "existing key" do
|
50
|
+
before do
|
51
|
+
source['baz'] = 'wick'
|
52
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar'}}, options)
|
53
|
+
@result = subject.read('foo')
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns value" do
|
57
|
+
@result.should eq('bar')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "clears and loads source hash" do
|
61
|
+
source.should eq({
|
62
|
+
'_id' => id,
|
63
|
+
'foo' => 'bar',
|
64
|
+
})
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "missing key" do
|
69
|
+
before do
|
70
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar'}}, options)
|
71
|
+
@result = subject.read('apple')
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns nil" do
|
75
|
+
@result.should be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "missing document" do
|
80
|
+
before do
|
81
|
+
@result = subject.read('foo')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "returns nil" do
|
85
|
+
@result.should be_nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#write" do
|
91
|
+
context "existing key" do
|
92
|
+
before do
|
93
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar'}}, options)
|
94
|
+
subject.write('foo', 'new value')
|
95
|
+
end
|
96
|
+
|
97
|
+
it "sets key" do
|
98
|
+
document.fetch('foo').should eq('new value')
|
99
|
+
source.fetch('foo').should eq('new value')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "missing key" do
|
104
|
+
before do
|
105
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar'}}, options)
|
106
|
+
subject.write('apple', 'orange')
|
107
|
+
end
|
108
|
+
|
109
|
+
it "sets key" do
|
110
|
+
document.fetch('apple').should eq('orange')
|
111
|
+
source.fetch('apple').should eq('orange')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "missing document" do
|
116
|
+
before do
|
117
|
+
subject.write('foo', 'bar')
|
118
|
+
end
|
119
|
+
|
120
|
+
it "creates document" do
|
121
|
+
document.should_not be_nil
|
122
|
+
end
|
123
|
+
|
124
|
+
it "sets key" do
|
125
|
+
document.fetch('foo').should eq('bar')
|
126
|
+
source.fetch('foo').should eq('bar')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#delete" do
|
132
|
+
before do
|
133
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar', 'apple' => 'orange'}}, options)
|
134
|
+
@result = subject.delete('foo')
|
135
|
+
end
|
136
|
+
|
137
|
+
it "removes the key" do
|
138
|
+
document.key?('foo').should be_false
|
139
|
+
source.key?('foo').should be_false
|
140
|
+
end
|
141
|
+
|
142
|
+
it "does not remove other keys" do
|
143
|
+
document.fetch('apple').should eq('orange')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#set_members" do
|
148
|
+
context "existing key" do
|
149
|
+
before do
|
150
|
+
collection.update(criteria, {'$set' => {'people' => [1, 2, 3], 'foo' => 'bar'}}, options)
|
151
|
+
@result = subject.set_members('people')
|
152
|
+
end
|
153
|
+
|
154
|
+
it "returns set" do
|
155
|
+
@result.should eq(Set[1, 2, 3])
|
156
|
+
end
|
157
|
+
|
158
|
+
it "loads source hash" do
|
159
|
+
source.should eq({
|
160
|
+
'_id' => id,
|
161
|
+
'people' => Set[1, 2, 3],
|
162
|
+
'foo' => 'bar',
|
163
|
+
})
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "missing key" do
|
168
|
+
before do
|
169
|
+
collection.update(criteria, {'$set' => {'people' => [1, 2, 3]}}, options)
|
170
|
+
@result = subject.set_members('users')
|
171
|
+
end
|
172
|
+
|
173
|
+
it "returns empty set" do
|
174
|
+
@result.should eq(Set.new)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "missing document" do
|
179
|
+
it "returns empty set" do
|
180
|
+
subject.set_members('people').should eq(Set.new)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "#set_add" do
|
186
|
+
context "existing key" do
|
187
|
+
before do
|
188
|
+
collection.update(criteria, {'$set' => {'people' => [1, 2, 3]}}, options)
|
189
|
+
subject.set_add('people', 4)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "adds value to set" do
|
193
|
+
document.fetch('people').should eq([1, 2, 3, 4])
|
194
|
+
source.fetch('people').should eq(Set[1, 2, 3, 4])
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context "missing key" do
|
199
|
+
before do
|
200
|
+
collection.update(criteria, {'$set' => {'people' => [1, 2, 3]}}, options)
|
201
|
+
subject.set_add('users', 1)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "adds value to set" do
|
205
|
+
document.fetch('users').should eq([1])
|
206
|
+
source.fetch('users').should eq(Set[1])
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
context "missing document" do
|
211
|
+
before do
|
212
|
+
subject.set_add('people', 1)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "creates document" do
|
216
|
+
document.should_not be_nil
|
217
|
+
end
|
218
|
+
|
219
|
+
it "adds value to set" do
|
220
|
+
document.fetch('people').should eq([1])
|
221
|
+
source.fetch('people').should eq(Set[1])
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "#set_delete" do
|
227
|
+
context "existing key" do
|
228
|
+
before do
|
229
|
+
collection.update(criteria, {'$set' => {'people' => [1, 2, 3]}}, options)
|
230
|
+
subject.set_delete 'people', 3
|
231
|
+
end
|
232
|
+
|
233
|
+
it "removes value to key" do
|
234
|
+
document.fetch('people').should eq([1, 2])
|
235
|
+
source.fetch('people').should eq(Set[1, 2])
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context "missing key" do
|
240
|
+
before do
|
241
|
+
collection.update(criteria, {'$set' => {'people' => [1, 2, 3]}}, options)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "does not error" do
|
245
|
+
expect { subject.set_delete 'foo', 1 }.to_not raise_error
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context "missing document" do
|
250
|
+
it "does not error" do
|
251
|
+
expect { subject.set_delete 'foo', 1 }.to_not raise_error
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "#clear" do
|
257
|
+
before do
|
258
|
+
collection.update(criteria, {'$set' => {'foo' => 'bar'}}, options)
|
259
|
+
subject.read('foo') # load the source hash
|
260
|
+
subject.clear
|
261
|
+
end
|
262
|
+
|
263
|
+
it "clears the source hash" do
|
264
|
+
source.should be_empty
|
265
|
+
end
|
266
|
+
|
267
|
+
it "does not remove the document" do
|
268
|
+
document.should_not be_empty
|
269
|
+
end
|
270
|
+
|
271
|
+
it "marks the document as not loaded" do
|
272
|
+
subject.loaded?.should be_false
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'flipper/adapters/mongo_single_document'
|
3
|
+
require 'flipper/spec/shared_adapter_specs'
|
4
|
+
|
5
|
+
describe Flipper::Adapters::MongoSingleDocument do
|
6
|
+
let(:collection) { Mongo::Connection.new.db('testing')['testing'] }
|
7
|
+
let(:criteria) { {:_id => id} }
|
8
|
+
let(:id) { 'flipper' }
|
9
|
+
|
10
|
+
subject { described_class.new(collection, :id => id) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
collection.remove(criteria)
|
14
|
+
end
|
15
|
+
|
16
|
+
def read_key(key)
|
17
|
+
if (doc = collection.find_one(criteria))
|
18
|
+
value = doc[key]
|
19
|
+
|
20
|
+
if value.is_a?(::Array)
|
21
|
+
value = value.to_set
|
22
|
+
end
|
23
|
+
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_key(key, value)
|
29
|
+
if value.is_a?(::Set)
|
30
|
+
value = value.to_a
|
31
|
+
end
|
32
|
+
|
33
|
+
options = {:upsert => true}
|
34
|
+
updates = {'$set' => {key => value}}
|
35
|
+
collection.update criteria, updates, options
|
36
|
+
end
|
37
|
+
|
38
|
+
it_should_behave_like 'a flipper adapter'
|
39
|
+
end
|
@@ -4,18 +4,17 @@ require 'flipper/spec/shared_adapter_specs'
|
|
4
4
|
|
5
5
|
describe Flipper::Adapters::Mongo do
|
6
6
|
let(:collection) { Mongo::Connection.new.db('testing')['testing'] }
|
7
|
-
let(:
|
8
|
-
let(:id) { described_class::DefaultId }
|
7
|
+
let(:id) { 'flipper' }
|
9
8
|
|
10
|
-
subject {
|
9
|
+
subject { described_class.new(collection) }
|
11
10
|
|
12
11
|
before do
|
13
|
-
collection.remove
|
12
|
+
collection.remove
|
14
13
|
end
|
15
14
|
|
16
15
|
def read_key(key)
|
17
|
-
if (doc = collection.find_one(
|
18
|
-
value = doc[
|
16
|
+
if (doc = collection.find_one(:_id => key))
|
17
|
+
value = doc['v']
|
19
18
|
|
20
19
|
if value.is_a?(::Array)
|
21
20
|
value = value.to_set
|
@@ -30,8 +29,9 @@ describe Flipper::Adapters::Mongo do
|
|
30
29
|
value = value.to_a
|
31
30
|
end
|
32
31
|
|
33
|
-
|
34
|
-
updates
|
32
|
+
criteria = {:_id => key}
|
33
|
+
updates = {'$set' => {'v' => value}}
|
34
|
+
options = {:upsert => true}
|
35
35
|
collection.update criteria, updates, options
|
36
36
|
end
|
37
37
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper-mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,19 +9,19 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: flipper
|
16
|
-
requirement: &
|
16
|
+
requirement: &70285634449460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: '0.2'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70285634449460
|
25
25
|
description: Mongo adapter for Flipper
|
26
26
|
email:
|
27
27
|
- nunemaker@gmail.com
|
@@ -38,10 +38,12 @@ files:
|
|
38
38
|
- flipper-mongo.gemspec
|
39
39
|
- lib/flipper-mongo.rb
|
40
40
|
- lib/flipper/adapters/mongo.rb
|
41
|
+
- lib/flipper/adapters/mongo/document.rb
|
41
42
|
- lib/flipper/adapters/mongo/version.rb
|
42
|
-
- lib/flipper/adapters/
|
43
|
+
- lib/flipper/adapters/mongo_single_document.rb
|
44
|
+
- spec/flipper/adapters/mongo/document_spec.rb
|
45
|
+
- spec/flipper/adapters/mongo_single_document_spec.rb
|
43
46
|
- spec/flipper/adapters/mongo_spec.rb
|
44
|
-
- spec/flipper/adapters/mongo_with_ttl_spec.rb
|
45
47
|
- spec/helper.rb
|
46
48
|
- spec/support/accessor_helpers.rb
|
47
49
|
homepage: http://jnunemaker.github.com/flipper-mongo
|
@@ -58,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
60
|
version: '0'
|
59
61
|
segments:
|
60
62
|
- 0
|
61
|
-
hash: -
|
63
|
+
hash: -10539439190267456
|
62
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
65
|
none: false
|
64
66
|
requirements:
|
@@ -67,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
69
|
version: '0'
|
68
70
|
segments:
|
69
71
|
- 0
|
70
|
-
hash: -
|
72
|
+
hash: -10539439190267456
|
71
73
|
requirements: []
|
72
74
|
rubyforge_project:
|
73
75
|
rubygems_version: 1.8.10
|
@@ -75,7 +77,8 @@ signing_key:
|
|
75
77
|
specification_version: 3
|
76
78
|
summary: Mongo adapter for Flipper
|
77
79
|
test_files:
|
80
|
+
- spec/flipper/adapters/mongo/document_spec.rb
|
81
|
+
- spec/flipper/adapters/mongo_single_document_spec.rb
|
78
82
|
- spec/flipper/adapters/mongo_spec.rb
|
79
|
-
- spec/flipper/adapters/mongo_with_ttl_spec.rb
|
80
83
|
- spec/helper.rb
|
81
84
|
- spec/support/accessor_helpers.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
require 'mongo'
|
3
|
-
require 'flipper/adapters/mongo'
|
4
|
-
|
5
|
-
module Flipper
|
6
|
-
module Adapters
|
7
|
-
class MongoWithTTL < Mongo
|
8
|
-
private
|
9
|
-
|
10
|
-
# Override Mongo adapter's load
|
11
|
-
def load
|
12
|
-
if expired?
|
13
|
-
@document = fresh_load
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def fresh_load
|
18
|
-
@last_load_at = Time.now.to_i
|
19
|
-
@collection.find_one(@mongo_criteria) || {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def ttl
|
23
|
-
@options.fetch(:ttl) { 0 }
|
24
|
-
end
|
25
|
-
|
26
|
-
def expired?
|
27
|
-
return true if never_loaded?
|
28
|
-
Time.now.to_i >= (@last_load_at + ttl)
|
29
|
-
end
|
30
|
-
|
31
|
-
def never_loaded?
|
32
|
-
@last_load_at.nil?
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'flipper/adapters/mongo_with_ttl'
|
3
|
-
require 'flipper/spec/shared_adapter_specs'
|
4
|
-
|
5
|
-
describe Flipper::Adapters::MongoWithTTL do
|
6
|
-
let(:collection) { Mongo::Connection.new.db('testing')['testing'] }
|
7
|
-
let(:criteria) { {:_id => id} }
|
8
|
-
let(:id) { described_class::DefaultId }
|
9
|
-
|
10
|
-
subject { Flipper::Adapters::MongoWithTTL.new(collection) }
|
11
|
-
|
12
|
-
before do
|
13
|
-
collection.remove(criteria)
|
14
|
-
end
|
15
|
-
|
16
|
-
it_should_behave_like 'a flipper adapter'
|
17
|
-
|
18
|
-
it "can cache document in process for a number of seconds" do
|
19
|
-
options = {:ttl => 10}
|
20
|
-
adapter = Flipper::Adapters::MongoWithTTL.new(collection, options)
|
21
|
-
adapter.write('foo', 'bar')
|
22
|
-
now = Time.now
|
23
|
-
Timecop.freeze(now)
|
24
|
-
|
25
|
-
collection.should_receive(:find_one).with(:_id => id)
|
26
|
-
adapter.read('foo')
|
27
|
-
|
28
|
-
adapter.read('foo')
|
29
|
-
adapter.read('bar')
|
30
|
-
|
31
|
-
Timecop.travel(3)
|
32
|
-
adapter.read('foo')
|
33
|
-
|
34
|
-
Timecop.travel(6)
|
35
|
-
adapter.read('foo')
|
36
|
-
|
37
|
-
collection.should_receive(:find_one).with(:_id => id)
|
38
|
-
Timecop.travel(1)
|
39
|
-
adapter.read('foo')
|
40
|
-
|
41
|
-
Timecop.travel(4)
|
42
|
-
adapter.read('foo')
|
43
|
-
end
|
44
|
-
end
|