zermelo 1.1.0 → 1.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.
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