zermelo 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +76 -52
  4. data/lib/zermelo/associations/association_data.rb +4 -3
  5. data/lib/zermelo/associations/class_methods.rb +37 -50
  6. data/lib/zermelo/associations/index.rb +3 -1
  7. data/lib/zermelo/associations/multiple.rb +247 -0
  8. data/lib/zermelo/associations/range_index.rb +44 -0
  9. data/lib/zermelo/associations/singular.rb +193 -0
  10. data/lib/zermelo/associations/unique_index.rb +4 -3
  11. data/lib/zermelo/backend.rb +120 -0
  12. data/lib/zermelo/backends/{influxdb_backend.rb → influxdb.rb} +87 -31
  13. data/lib/zermelo/backends/{redis_backend.rb → redis.rb} +53 -58
  14. data/lib/zermelo/backends/stub.rb +43 -0
  15. data/lib/zermelo/filter.rb +194 -0
  16. data/lib/zermelo/filters/index_range.rb +22 -0
  17. data/lib/zermelo/filters/{influxdb_filter.rb → influxdb.rb} +12 -11
  18. data/lib/zermelo/filters/redis.rb +173 -0
  19. data/lib/zermelo/filters/steps/list_step.rb +48 -30
  20. data/lib/zermelo/filters/steps/set_step.rb +148 -89
  21. data/lib/zermelo/filters/steps/sort_step.rb +2 -2
  22. data/lib/zermelo/record.rb +53 -0
  23. data/lib/zermelo/records/attributes.rb +32 -0
  24. data/lib/zermelo/records/class_methods.rb +12 -25
  25. data/lib/zermelo/records/{influxdb_record.rb → influxdb.rb} +3 -4
  26. data/lib/zermelo/records/instance_methods.rb +9 -8
  27. data/lib/zermelo/records/key.rb +3 -1
  28. data/lib/zermelo/records/redis.rb +17 -0
  29. data/lib/zermelo/records/stub.rb +17 -0
  30. data/lib/zermelo/version.rb +1 -1
  31. data/spec/lib/zermelo/associations/index_spec.rb +70 -1
  32. data/spec/lib/zermelo/associations/multiple_spec.rb +1084 -0
  33. data/spec/lib/zermelo/associations/range_index_spec.rb +77 -0
  34. data/spec/lib/zermelo/associations/singular_spec.rb +149 -0
  35. data/spec/lib/zermelo/associations/unique_index_spec.rb +58 -2
  36. data/spec/lib/zermelo/filter_spec.rb +363 -0
  37. data/spec/lib/zermelo/locks/redis_lock_spec.rb +3 -3
  38. data/spec/lib/zermelo/records/instance_methods_spec.rb +206 -0
  39. data/spec/spec_helper.rb +9 -1
  40. data/spec/support/mock_logger.rb +48 -0
  41. metadata +31 -46
  42. data/lib/zermelo/associations/belongs_to.rb +0 -115
  43. data/lib/zermelo/associations/has_and_belongs_to_many.rb +0 -128
  44. data/lib/zermelo/associations/has_many.rb +0 -120
  45. data/lib/zermelo/associations/has_one.rb +0 -109
  46. data/lib/zermelo/associations/has_sorted_set.rb +0 -124
  47. data/lib/zermelo/backends/base.rb +0 -115
  48. data/lib/zermelo/filters/base.rb +0 -212
  49. data/lib/zermelo/filters/redis_filter.rb +0 -111
  50. data/lib/zermelo/filters/steps/sorted_set_step.rb +0 -156
  51. data/lib/zermelo/records/base.rb +0 -62
  52. data/lib/zermelo/records/redis_record.rb +0 -27
  53. data/spec/lib/zermelo/associations/belongs_to_spec.rb +0 -6
  54. data/spec/lib/zermelo/associations/has_many_spec.rb +0 -6
  55. data/spec/lib/zermelo/associations/has_one_spec.rb +0 -6
  56. data/spec/lib/zermelo/associations/has_sorted_set.spec.rb +0 -6
  57. data/spec/lib/zermelo/backends/influxdb_backend_spec.rb +0 -0
  58. data/spec/lib/zermelo/backends/moneta_backend_spec.rb +0 -0
  59. data/spec/lib/zermelo/filters/influxdb_filter_spec.rb +0 -0
  60. data/spec/lib/zermelo/filters/redis_filter_spec.rb +0 -0
  61. data/spec/lib/zermelo/records/influxdb_record_spec.rb +0 -434
  62. data/spec/lib/zermelo/records/key_spec.rb +0 -6
  63. data/spec/lib/zermelo/records/redis_record_spec.rb +0 -1461
  64. data/spec/lib/zermelo/records/type_validator_spec.rb +0 -6
  65. data/spec/lib/zermelo/version_spec.rb +0 -6
  66. data/spec/lib/zermelo_spec.rb +0 -6
@@ -1,434 +0,0 @@
1
- require 'spec_helper'
2
- require 'zermelo/records/influxdb_record'
3
-
4
- describe Zermelo::Records::InfluxDBRecord, :influxdb => true do
5
-
6
- module Zermelo
7
- class InfluxDBExample
8
- include Zermelo::Records::InfluxDBRecord
9
-
10
- define_attributes :name => :string,
11
- :email => :string,
12
- :active => :boolean
13
-
14
- validates :name, :presence => true
15
-
16
- has_many :children, :class_name => 'Zermelo::InfluxDBChild'
17
- has_sorted_set :sorted, :class_name => 'Zermelo::InfluxDBSorted'
18
- end
19
-
20
- class InfluxDBChild
21
- include Zermelo::Records::InfluxDBRecord
22
-
23
- define_attributes :name => :string,
24
- :important => :boolean
25
-
26
- belongs_to :example, :class_name => 'Zermelo::InfluxDBExample', :inverse_of => :children
27
-
28
- validates :name, :presence => true
29
- end
30
-
31
- class InfluxDBSorted
32
- include Zermelo::Records::InfluxDBRecord
33
-
34
- define_attributes :name => :string,
35
- :important => :boolean
36
-
37
- belongs_to :example, :class_name => 'Zermelo::InfluxDBExample', :inverse_of => :sorted
38
-
39
- validates :name, :presence => true
40
- end
41
- end
42
-
43
- def create_example(attrs = {})
44
- Zermelo.influxdb.write_point("influx_db_example/#{attrs[:id]}", attrs)
45
- end
46
-
47
- let(:influxdb) { Zermelo.influxdb }
48
-
49
- it "is invalid without a name" do
50
- example = Zermelo::InfluxDBExample.new(:id => '1',
51
- :email => 'jsmith@example.com', :active => true)
52
- expect(example).not_to be_valid
53
-
54
- errs = example.errors
55
- expect(errs).not_to be_nil
56
- expect(errs[:name]).to eq(["can't be blank"])
57
- end
58
-
59
- it "adds a record's attributes to influxdb" do
60
- begin
61
- data = Zermelo.influxdb.query("select * from /influx_db_example\\/1/")['influx_db_example/1']
62
- expect(data).to be_nil
63
- rescue InfluxDB::Error => ide
64
- # only happens occasionally, with an empty time series by that name
65
- raise unless /^Couldn't look up columns$/ === ide.message
66
- end
67
-
68
- example = Zermelo::InfluxDBExample.new(:id => '1', :name => 'John Smith',
69
- :email => 'jsmith@example.com', :active => true)
70
- expect(example).to be_valid
71
- expect(example.save).to be_truthy
72
-
73
- data = Zermelo.influxdb.query("select * from /influx_db_example\\/1/")['influx_db_example/1']
74
- expect(data).to be_an(Array)
75
- expect(data.size).to eql(1)
76
- record = data.first
77
- expect(record).to be_a(Hash)
78
- # FIXME boolean is stringified as redis needs it to be like that --
79
- # should probably make this backend-dependent
80
- expect(record).to include("name"=>"John Smith",
81
- "email"=>"jsmith@example.com", "active"=>"true", "id"=>"1")
82
- end
83
-
84
- it "finds a record by id in influxdb" do
85
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
86
- :active => 'true')
87
-
88
- example = Zermelo::InfluxDBExample.find_by_id('1')
89
- expect(example).not_to be_nil
90
-
91
- expect(example).to respond_to(:name)
92
- expect(example.name).to eql('Jane Doe')
93
- expect(example).to respond_to(:email)
94
- expect(example.email).to eql('jdoe@example.com')
95
- expect(example).to respond_to(:active)
96
- expect(example.active).to be true
97
- end
98
-
99
- it "can update a value in influxdb" do
100
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
101
- :active => 'true')
102
-
103
- example = Zermelo::InfluxDBExample.find_by_id('1')
104
- expect(example).not_to be_nil
105
-
106
- example.name = 'John Smith'
107
- example.save
108
-
109
- other_example = Zermelo::InfluxDBExample.find_by_id('1')
110
- expect(other_example).not_to be_nil
111
- expect(other_example.name).to eq('John Smith')
112
- end
113
-
114
- it "destroys a single record from influxdb" do
115
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
116
- :active => 'true')
117
-
118
- example = Zermelo::InfluxDBExample.find_by_id('1')
119
- example.destroy
120
- example_chk = Zermelo::InfluxDBExample.find_by_id('1')
121
- expect(example_chk).to be_nil
122
- end
123
-
124
- it "resets changed state on refresh" do
125
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
126
- :active => 'true')
127
- example = Zermelo::InfluxDBExample.find_by_id('1')
128
-
129
- example.name = "King Henry VIII"
130
- expect(example.changed).to include('name')
131
- expect(example.changes).to eq({'name' => ['Jane Doe', 'King Henry VIII']})
132
-
133
- example.refresh
134
- expect(example.changed).to be_empty
135
- expect(example.changes).to be_empty
136
- end
137
-
138
- context 'filters' do
139
-
140
- it "returns all record ids" do
141
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
142
- :active => 'true')
143
- create_example(:id => '2', :name => 'John Smith',
144
- :email => 'jsmith@example.com', :active => 'false')
145
-
146
- examples = Zermelo::InfluxDBExample.ids
147
- expect(examples).not_to be_nil
148
- expect(examples).to be_an(Array)
149
- expect(examples.size).to eq(2)
150
- expect(examples).to contain_exactly('2', '1')
151
- end
152
-
153
- it "returns a count of records" do
154
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
155
- :active => 'true')
156
- create_example(:id => '2', :name => 'John Smith',
157
- :email => 'jsmith@example.com', :active => 'false')
158
-
159
- example_count = Zermelo::InfluxDBExample.count
160
- expect(example_count).not_to be_nil
161
- expect(example_count).to be_an(Integer)
162
- expect(example_count).to eq(2)
163
- end
164
-
165
- it "returns all records" do
166
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
167
- :active => 'true')
168
- create_example(:id => '2', :name => 'John Smith',
169
- :email => 'jsmith@example.com', :active => 'false')
170
-
171
- examples = Zermelo::InfluxDBExample.all
172
- expect(examples).not_to be_nil
173
- expect(examples).to be_an(Array)
174
- expect(examples.size).to eq(2)
175
- expect(examples.map(&:id)).to contain_exactly('2', '1')
176
- end
177
-
178
- it "filters all class records by attribute values" do
179
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
180
- :active => 'true')
181
- create_example(:id => '2', :name => 'John Smith',
182
- :email => 'jsmith@example.com', :active => 'false')
183
-
184
- example = Zermelo::InfluxDBExample.intersect(:active => true).all
185
- expect(example).not_to be_nil
186
- expect(example).to be_an(Array)
187
- expect(example.size).to eq(1)
188
- expect(example.map(&:id)).to eq(['1'])
189
- end
190
-
191
- it "chains two intersect filters together" do
192
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
193
- :active => 'true')
194
- create_example(:id => '2', :name => 'John Smith',
195
- :email => 'jsmith@example.com', :active => 'false')
196
- create_example(:id => '3', :name => 'Fred Bloggs',
197
- :email => 'fbloggs@example.com', :active => 'true')
198
-
199
- example = Zermelo::InfluxDBExample.intersect(:active => true).
200
- intersect(:name => 'Jane Doe').all
201
- expect(example).not_to be_nil
202
- expect(example).to be_an(Array)
203
- expect(example.size).to eq(1)
204
- expect(example.map(&:id)).to eq(['1'])
205
- end
206
-
207
- it "allows multiple attributes in an intersect filter" do
208
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
209
- :active => 'true')
210
- create_example(:id => '2', :name => 'John Smith',
211
- :email => 'jsmith@example.com', :active => 'false')
212
- create_example(:id => '3', :name => 'Fred Bloggs',
213
- :email => 'fbloggs@example.com', :active => 'true')
214
-
215
- example = Zermelo::InfluxDBExample.intersect(:active => true,
216
- :name => 'Jane Doe').all
217
- expect(example).not_to be_nil
218
- expect(example).to be_an(Array)
219
- expect(example.size).to eq(1)
220
- expect(example.map(&:id)).to eq(['1'])
221
- end
222
-
223
- it "chains an intersect and a union filter together" do
224
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
225
- :active => 'true')
226
- create_example(:id => '2', :name => 'John Smith',
227
- :email => 'jsmith@example.com', :active => 'false')
228
- create_example(:id => '3', :name => 'Fred Bloggs',
229
- :email => 'fbloggs@example.com', :active => 'false')
230
-
231
- example = Zermelo::InfluxDBExample.intersect(:active => true).union(:name => 'Fred Bloggs').all
232
- expect(example).not_to be_nil
233
- expect(example).to be_an(Array)
234
- expect(example.size).to eq(2)
235
- expect(example.map(&:id)).to contain_exactly('3', '1')
236
- end
237
-
238
- it "chains an intersect and a diff filter together" do
239
- create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
240
- :active => 'true')
241
- create_example(:id => '2', :name => 'John Smith',
242
- :email => 'jsmith@example.com', :active => 'false')
243
- create_example(:id => '3', :name => 'Fred Bloggs',
244
- :email => 'fbloggs@example.com', :active => 'false')
245
-
246
- example = Zermelo::InfluxDBExample.intersect(:active => false).diff(:name => 'Fred Bloggs').all
247
- expect(example).not_to be_nil
248
- expect(example).to be_an(Array)
249
- expect(example.size).to eq(1)
250
- expect(example.map(&:id)).to eq(['2'])
251
- end
252
-
253
- end
254
-
255
- context 'has_many association' do
256
-
257
- it "sets a parent/child has_many relationship between two records in influxdb" do
258
- create_example(:id => '8', :name => 'John Jones',
259
- :email => 'jjones@example.com', :active => 'true')
260
- example = Zermelo::InfluxDBExample.find_by_id('8')
261
-
262
- child = Zermelo::InfluxDBChild.new(:id => '3', :name => 'Abel Tasman')
263
- expect(child.save).to be_truthy
264
-
265
- children = example.children.all
266
-
267
- expect(children).to be_an(Array)
268
- expect(children).to be_empty
269
-
270
- example.children << child
271
-
272
- children = example.children.all
273
-
274
- expect(children).to be_an(Array)
275
- expect(children.size).to eq(1)
276
- end
277
-
278
- it "applies an intersect filter to a has_many association" do
279
- create_example(:id => '8', :name => 'John Jones',
280
- :email => 'jjones@example.com', :active => 'true')
281
- example = Zermelo::InfluxDBExample.find_by_id('8')
282
-
283
- child_1 = Zermelo::InfluxDBChild.new(:id => '3', :name => 'John Smith')
284
- expect(child_1.save).to be_truthy
285
-
286
- child_2 = Zermelo::InfluxDBChild.new(:id => '4', :name => 'Jane Doe')
287
- expect(child_2.save).to be_truthy
288
-
289
- example.children.add(child_1, child_2)
290
- expect(example.children.count).to eq(2)
291
-
292
- result = example.children.intersect(:name => 'John Smith').all
293
- expect(result).to be_an(Array)
294
- expect(result.size).to eq(1)
295
- expect(result.map(&:id)).to eq(['3'])
296
- end
297
-
298
- it "applies chained intersect and union filters to a has_many association" do
299
- create_example(:id => '8', :name => 'John Jones',
300
- :email => 'jjones@example.com', :active => 'true')
301
- example = Zermelo::InfluxDBExample.find_by_id('8')
302
-
303
- child_1 = Zermelo::InfluxDBChild.new(:id => '3', :name => 'John Smith')
304
- expect(child_1.save).to be_truthy
305
-
306
- child_2 = Zermelo::InfluxDBChild.new(:id => '4', :name => 'Jane Doe')
307
- expect(child_2.save).to be_truthy
308
-
309
- example.children.add(child_1, child_2)
310
- expect(example.children.count).to eq(2)
311
-
312
- result = example.children.intersect(:name => 'John Smith').union(:id => '4').all
313
- expect(result).to be_an(Array)
314
- expect(result.size).to eq(2)
315
- expect(result.map(&:id)).to eq(['3', '4'])
316
- end
317
-
318
- end
319
-
320
- context 'has_sorted_set association' do
321
-
322
- let(:time_i) { Time.now.to_i }
323
-
324
- it "sets a parent/child has_sorted_set relationship between two records in influxdb" do
325
- create_example(:id => '8', :name => 'John Jones',
326
- :email => 'jjones@example.com', :active => 'true')
327
- example = Zermelo::InfluxDBExample.find_by_id('8')
328
-
329
- sorted_1 = Zermelo::InfluxDBSorted.new(:id => '3', :name => 'Abel Tasman', :time => time_i)
330
- expect(sorted_1.save).to be_truthy
331
-
332
- sorted_2 = Zermelo::InfluxDBSorted.new(:id => '4', :name => 'Joe Smith', :time => time_i - 60)
333
- expect(sorted_2.save).to be_truthy
334
-
335
- sorted = example.sorted.all
336
-
337
- expect(sorted).to be_an(Array)
338
- expect(sorted).to be_empty
339
-
340
- example.sorted.add(sorted_1, sorted_2)
341
-
342
- sorted = example.sorted.all
343
-
344
- expect(sorted).to be_an(Array)
345
- expect(sorted.size).to eq(2)
346
- expect(sorted.map(&:id)).to eq(['3', '4'])
347
- end
348
-
349
- it "applies an intersect filter to a has_sorted_set association" do
350
- create_example(:id => '8', :name => 'John Jones',
351
- :email => 'jjones@example.com', :active => 'true')
352
- example = Zermelo::InfluxDBExample.find_by_id('8')
353
-
354
- sorted_1 = Zermelo::InfluxDBSorted.new(:id => '3', :name => 'Abel Tasman', :time => time_i)
355
- expect(sorted_1.save).to be_truthy
356
-
357
- sorted_2 = Zermelo::InfluxDBSorted.new(:id => '4', :name => 'Joe Smith', :time => time_i - 60)
358
- expect(sorted_2.save).to be_truthy
359
-
360
- example.sorted.add(sorted_1, sorted_2)
361
-
362
- result = example.sorted.intersect(:id => '3').all
363
- expect(result).to be_an(Array)
364
- expect(result.size).to eq(1)
365
- expect(result.map(&:id)).to eq(['3'])
366
- end
367
-
368
- it "applies an intersect_range filter to a has_sorted_set association" do
369
- create_example(:id => '8', :name => 'John Jones',
370
- :email => 'jjones@example.com', :active => 'true')
371
- example = Zermelo::InfluxDBExample.find_by_id('8')
372
-
373
- sorted_1 = Zermelo::InfluxDBSorted.new(:id => '3', :name => 'Abel Tasman', :time => time_i)
374
- expect(sorted_1.save).to be_truthy
375
-
376
- sorted_2 = Zermelo::InfluxDBSorted.new(:id => '4', :name => 'Joe Smith', :time => time_i - 60)
377
- expect(sorted_2.save).to be_truthy
378
-
379
- example.sorted.add(sorted_1, sorted_2)
380
-
381
- result = example.sorted.intersect_range(time_i - 30, time_i + 30).all
382
- expect(result).to be_an(Array)
383
- expect(result.size).to eq(1)
384
- expect(result.map(&:id)).to eq(['3'])
385
- end
386
-
387
- it "applies chained intersect and union filters to a has_sorted_set association" do
388
- create_example(:id => '8', :name => 'John Jones',
389
- :email => 'jjones@example.com', :active => 'true')
390
- example = Zermelo::InfluxDBExample.find_by_id('8')
391
-
392
- sorted_1 = Zermelo::InfluxDBSorted.new(:id => '3', :name => 'Abel Tasman', :time => time_i)
393
- expect(sorted_1.save).to be_truthy
394
-
395
- sorted_2 = Zermelo::InfluxDBSorted.new(:id => '4', :name => 'Joe Smith', :time => time_i - 60)
396
- expect(sorted_2.save).to be_truthy
397
-
398
- sorted_3 = Zermelo::InfluxDBSorted.new(:id => '5', :name => 'John Trugg', :time => time_i - 90)
399
- expect(sorted_3.save).to be_truthy
400
-
401
- example.sorted.add(sorted_1, sorted_2, sorted_3)
402
-
403
- result = example.sorted.intersect(:name => 'Abel Tasman').union(:id => '4').all
404
- expect(result).to be_an(Array)
405
- expect(result.size).to eq(2)
406
- expect(result.map(&:id)).to eq(['3', '4'])
407
- end
408
-
409
- # # See https://github.com/flapjack/zermelo/issues/15
410
- # it "applies chained intersect_range and union filters to a has_sorted_set association" do
411
- # create_example(:id => '8', :name => 'John Jones',
412
- # :email => 'jjones@example.com', :active => 'true')
413
- # example = Zermelo::InfluxDBExample.find_by_id('8')
414
-
415
- # sorted_1 = Zermelo::InfluxDBSorted.new(:id => '3', :name => 'Abel Tasman', :time => time_i - 30)
416
- # expect(sorted_1.save).to be_truthy
417
-
418
- # sorted_2 = Zermelo::InfluxDBSorted.new(:id => '4', :name => 'Joe Smith', :time => time_i - 60)
419
- # expect(sorted_2.save).to be_truthy
420
-
421
- # sorted_3 = Zermelo::InfluxDBSorted.new(:id => '5', :name => 'John Trugg', :time => time_i - 90)
422
- # expect(sorted_3.save).to be_truthy
423
-
424
- # example.sorted.add(sorted_1, sorted_2, sorted_3)
425
-
426
- # result = example.sorted.intersect_range(time_i - 45, time_i - 15).union(:id => '4').all
427
- # expect(result).to be_an(Array)
428
- # expect(result.size).to eq(2)
429
- # expect(result.map(&:id)).to eq(['3', '4'])
430
- # end
431
-
432
- end
433
-
434
- end
@@ -1,6 +0,0 @@
1
- require 'spec_helper'
2
- require 'zermelo/records/key'
3
-
4
- describe Zermelo::Records::Key do
5
-
6
- end