zermelo 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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