zermelo 1.0.1 → 1.1.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.travis.yml +3 -5
  4. data/CHANGELOG.md +8 -2
  5. data/lib/zermelo/associations/belongs_to.rb +3 -3
  6. data/lib/zermelo/associations/has_and_belongs_to_many.rb +3 -3
  7. data/lib/zermelo/associations/has_many.rb +3 -3
  8. data/lib/zermelo/associations/has_one.rb +3 -3
  9. data/lib/zermelo/associations/has_sorted_set.rb +4 -4
  10. data/lib/zermelo/associations/index.rb +1 -2
  11. data/lib/zermelo/associations/unique_index.rb +1 -2
  12. data/lib/zermelo/backends/base.rb +1 -1
  13. data/lib/zermelo/backends/influxdb_backend.rb +29 -18
  14. data/lib/zermelo/backends/redis_backend.rb +106 -6
  15. data/lib/zermelo/filters/base.rb +34 -57
  16. data/lib/zermelo/filters/influxdb_filter.rb +22 -70
  17. data/lib/zermelo/filters/redis_filter.rb +35 -482
  18. data/lib/zermelo/filters/steps/list_step.rb +79 -0
  19. data/lib/zermelo/filters/steps/set_step.rb +176 -0
  20. data/lib/zermelo/filters/steps/sort_step.rb +85 -0
  21. data/lib/zermelo/filters/steps/sorted_set_step.rb +156 -0
  22. data/lib/zermelo/records/class_methods.rb +16 -4
  23. data/lib/zermelo/records/influxdb_record.rb +2 -0
  24. data/lib/zermelo/records/instance_methods.rb +4 -4
  25. data/lib/zermelo/records/key.rb +2 -0
  26. data/lib/zermelo/version.rb +1 -1
  27. data/lib/zermelo.rb +9 -1
  28. data/spec/lib/zermelo/records/influxdb_record_spec.rb +186 -10
  29. data/spec/lib/zermelo/records/redis_record_spec.rb +11 -4
  30. data/spec/spec_helper.rb +12 -10
  31. metadata +5 -11
  32. data/lib/zermelo/filters/steps/diff_range_step.rb +0 -17
  33. data/lib/zermelo/filters/steps/diff_step.rb +0 -17
  34. data/lib/zermelo/filters/steps/intersect_range_step.rb +0 -17
  35. data/lib/zermelo/filters/steps/intersect_step.rb +0 -17
  36. data/lib/zermelo/filters/steps/limit_step.rb +0 -17
  37. data/lib/zermelo/filters/steps/offset_step.rb +0 -17
  38. data/lib/zermelo/filters/steps/union_range_step.rb +0 -17
  39. data/lib/zermelo/filters/steps/union_step.rb +0 -17
  40. data/lib/zermelo/records/collection.rb +0 -14
@@ -13,11 +13,11 @@ describe Zermelo::Records::InfluxDBRecord, :influxdb => true do
13
13
 
14
14
  validates :name, :presence => true
15
15
 
16
- has_many :children, :class_name => 'Zermelo::InfluxDBExampleChild'
17
-
16
+ has_many :children, :class_name => 'Zermelo::InfluxDBChild'
17
+ has_sorted_set :sorted, :class_name => 'Zermelo::InfluxDBSorted'
18
18
  end
19
19
 
20
- class InfluxDBExampleChild
20
+ class InfluxDBChild
21
21
  include Zermelo::Records::InfluxDBRecord
22
22
 
23
23
  define_attributes :name => :string,
@@ -27,6 +27,17 @@ describe Zermelo::Records::InfluxDBRecord, :influxdb => true do
27
27
 
28
28
  validates :name, :presence => true
29
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
30
41
  end
31
42
 
32
43
  def create_example(attrs = {})
@@ -193,6 +204,22 @@ describe Zermelo::Records::InfluxDBRecord, :influxdb => true do
193
204
  expect(example.map(&:id)).to eq(['1'])
194
205
  end
195
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
+
196
223
  it "chains an intersect and a union filter together" do
197
224
  create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
198
225
  :active => 'true')
@@ -227,19 +254,14 @@ describe Zermelo::Records::InfluxDBRecord, :influxdb => true do
227
254
 
228
255
  context 'has_many association' do
229
256
 
230
- # def create_child(attrs = {})
231
- # Zermelo.influxdb.write_point('influx_db_example_child', attrs)
232
- # end
233
-
234
257
  it "sets a parent/child has_many relationship between two records in influxdb" do
235
258
  create_example(:id => '8', :name => 'John Jones',
236
259
  :email => 'jjones@example.com', :active => 'true')
260
+ example = Zermelo::InfluxDBExample.find_by_id('8')
237
261
 
238
- child = Zermelo::InfluxDBExampleChild.new(:id => '3', :name => 'Abel Tasman')
262
+ child = Zermelo::InfluxDBChild.new(:id => '3', :name => 'Abel Tasman')
239
263
  expect(child.save).to be_truthy
240
264
 
241
- example = Zermelo::InfluxDBExample.find_by_id('8')
242
-
243
265
  children = example.children.all
244
266
 
245
267
  expect(children).to be_an(Array)
@@ -253,6 +275,160 @@ describe Zermelo::Records::InfluxDBRecord, :influxdb => true do
253
275
  expect(children.size).to eq(1)
254
276
  end
255
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
+
256
432
  end
257
433
 
258
434
  end
@@ -395,6 +395,12 @@ describe Zermelo::Records::RedisRecord, :redis => true do
395
395
  expect(example.map(&:id)).to eq(['9', '8'])
396
396
  end
397
397
 
398
+ it "does not return a spurious record count when records don't exist" do
399
+ scope = Zermelo::RedisExample.intersect(:id => ['3000', '5000'])
400
+ expect(scope.all).to be_empty
401
+ expect(scope.count).to eq 0
402
+ end
403
+
398
404
  end
399
405
 
400
406
 
@@ -825,7 +831,7 @@ describe Zermelo::Records::RedisRecord, :redis => true do
825
831
  create_datum(example, :id => '6', :summary => 'aaargh', :timestamp => time.to_i + 20,
826
832
  :emotion => 'upset')
827
833
 
828
- data = example.data.intersect_range(0, 1, :desc => true).all
834
+ data = example.data.intersect_range(1, 2).sort(:id, :desc => true).all
829
835
 
830
836
  expect(data).not_to be_nil
831
837
  expect(data).to be_an(Array)
@@ -869,7 +875,7 @@ describe Zermelo::Records::RedisRecord, :redis => true do
869
875
  :emotion => 'upset')
870
876
 
871
877
  data = example.data.intersect_range(time.to_i - 1, time.to_i + 15,
872
- :desc => true, :by_score => true).all
878
+ :by_score => true).sort(:timestamp, :desc => true).all
873
879
  expect(data).not_to be_nil
874
880
  expect(data).to be_an(Array)
875
881
  expect(data.size).to eq(2)
@@ -935,7 +941,7 @@ describe Zermelo::Records::RedisRecord, :redis => true do
935
941
  create_datum(example, :id => '6', :summary => 'aaargh', :timestamp => time.to_i + 20,
936
942
  :emotion => 'upset')
937
943
 
938
- data = example.data.diff_range(0, 0, :desc => true).all
944
+ data = example.data.diff_range(2, 2).sort(:id, :desc => true).all
939
945
  expect(data).not_to be_nil
940
946
  expect(data).to be_an(Array)
941
947
  expect(data.size).to eq(2)
@@ -977,7 +983,8 @@ describe Zermelo::Records::RedisRecord, :redis => true do
977
983
  create_datum(example, :id => '6', :summary => 'aaargh', :timestamp => time.to_i + 20,
978
984
  :emotion => 'upset')
979
985
 
980
- data = example.data.diff_range(time.to_i - 1, time.to_i + 8, :by_score => true, :desc => true).all
986
+ data = example.data.diff_range(time.to_i - 1, time.to_i + 8, :by_score => true).
987
+ sort(:timestamp, :desc => true).all
981
988
  expect(data).not_to be_nil
982
989
  expect(data).to be_an(Array)
983
990
  expect(data.size).to eq(2)
data/spec/spec_helper.rb CHANGED
@@ -38,26 +38,28 @@ RSpec.configure do |config|
38
38
  # --seed 1234
39
39
  config.order = 'random'
40
40
 
41
- config.around(:each, :redis => true) do |example|
42
- # Zermelo.logger = ::Logger.new('tmp/spec.log')
41
+ config.before(:all, :redis => true) do
43
42
  Zermelo.redis = ::Redis.new(:db => 14)
43
+ end
44
+
45
+ config.before(:each, :redis => true) do
46
+ Zermelo.redis.select(14)
44
47
  Zermelo.redis.flushdb
45
- example.run
48
+ end
49
+
50
+ config.after(:all, :redis => true) do
46
51
  Zermelo.redis.quit
47
- # Zermelo.logger.debug('----')
48
- # Zermelo.logger = nil
49
52
  end
50
53
 
51
- config.around(:each, :influxdb => true) do |example|
52
- # Zermelo.logger = ::Logger.new('tmp/spec.log')
54
+ config.before(:all, :influxdb => true) do
53
55
  Zermelo.influxdb = InfluxDB::Client.new('zermelo_test',
54
56
  :username => 'zermelo', :password => 'zermelo', :retry => false)
57
+ end
58
+
59
+ config.before(:each, :influxdb => true) do
55
60
  Zermelo.influxdb.query('list series')['list_series_result'].each do |ser|
56
61
  Zermelo.influxdb.query("DELETE FROM \"#{ser['name']}\"")
57
62
  end
58
- example.run
59
- # Zermelo.logger.debug('----')
60
- # Zermelo.logger = nil
61
63
  end
62
64
 
63
65
  config.after(:each, :time => true) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zermelo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ali Graham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-04 00:00:00.000000000 Z
11
+ date: 2015-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -85,20 +85,14 @@ files:
85
85
  - lib/zermelo/filters/influxdb_filter.rb
86
86
  - lib/zermelo/filters/redis_filter.rb
87
87
  - lib/zermelo/filters/steps/base_step.rb
88
- - lib/zermelo/filters/steps/diff_range_step.rb
89
- - lib/zermelo/filters/steps/diff_step.rb
90
- - lib/zermelo/filters/steps/intersect_range_step.rb
91
- - lib/zermelo/filters/steps/intersect_step.rb
92
- - lib/zermelo/filters/steps/limit_step.rb
93
- - lib/zermelo/filters/steps/offset_step.rb
88
+ - lib/zermelo/filters/steps/list_step.rb
89
+ - lib/zermelo/filters/steps/set_step.rb
94
90
  - lib/zermelo/filters/steps/sort_step.rb
95
- - lib/zermelo/filters/steps/union_range_step.rb
96
- - lib/zermelo/filters/steps/union_step.rb
91
+ - lib/zermelo/filters/steps/sorted_set_step.rb
97
92
  - lib/zermelo/locks/no_lock.rb
98
93
  - lib/zermelo/locks/redis_lock.rb
99
94
  - lib/zermelo/records/base.rb
100
95
  - lib/zermelo/records/class_methods.rb
101
- - lib/zermelo/records/collection.rb
102
96
  - lib/zermelo/records/errors.rb
103
97
  - lib/zermelo/records/influxdb_record.rb
104
98
  - lib/zermelo/records/instance_methods.rb
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class DiffRangeStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:sorted_set]
9
- end
10
-
11
- def self.returns_type
12
- :sorted_set
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class DiffStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:set, :sorted_set]
9
- end
10
-
11
- def self.returns_type
12
- :set
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class IntersectRangeStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:sorted_set]
9
- end
10
-
11
- def self.returns_type
12
- :sorted_set
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class IntersectStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:set, :sorted_set]
9
- end
10
-
11
- def self.returns_type
12
- :set
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class LimitStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:list]
9
- end
10
-
11
- def self.returns_type
12
- :list
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class OffsetStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:list]
9
- end
10
-
11
- def self.returns_type
12
- :list
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class UnionRangeStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:sorted_set]
9
- end
10
-
11
- def self.returns_type
12
- :sorted_set
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- require 'zermelo/filters/steps/base_step'
2
-
3
- module Zermelo
4
- module Filters
5
- class Steps
6
- class UnionStep < Zermelo::Filters::Steps::BaseStep
7
- def self.accepted_types
8
- [:set, :sorted_set]
9
- end
10
-
11
- def self.returns_type
12
- :set
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,14 +0,0 @@
1
- module Zermelo
2
- module Records
3
- # high-level abstraction for a set or list of record ids
4
- class Collection
5
- attr_reader :klass, :name, :type
6
-
7
- def initialize(opts = {})
8
- @klass = opts[:class]
9
- @name = opts[:name]
10
- @type = opts[:type]
11
- end
12
- end
13
- end
14
- end