zermelo 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +10 -0
- data/.travis.yml +27 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +512 -0
- data/Rakefile +1 -0
- data/lib/zermelo/associations/association_data.rb +24 -0
- data/lib/zermelo/associations/belongs_to.rb +115 -0
- data/lib/zermelo/associations/class_methods.rb +244 -0
- data/lib/zermelo/associations/has_and_belongs_to_many.rb +128 -0
- data/lib/zermelo/associations/has_many.rb +120 -0
- data/lib/zermelo/associations/has_one.rb +109 -0
- data/lib/zermelo/associations/has_sorted_set.rb +124 -0
- data/lib/zermelo/associations/index.rb +50 -0
- data/lib/zermelo/associations/index_data.rb +18 -0
- data/lib/zermelo/associations/unique_index.rb +44 -0
- data/lib/zermelo/backends/base.rb +115 -0
- data/lib/zermelo/backends/influxdb_backend.rb +178 -0
- data/lib/zermelo/backends/redis_backend.rb +281 -0
- data/lib/zermelo/filters/base.rb +235 -0
- data/lib/zermelo/filters/influxdb_filter.rb +162 -0
- data/lib/zermelo/filters/redis_filter.rb +558 -0
- data/lib/zermelo/filters/steps/base_step.rb +22 -0
- data/lib/zermelo/filters/steps/diff_range_step.rb +17 -0
- data/lib/zermelo/filters/steps/diff_step.rb +17 -0
- data/lib/zermelo/filters/steps/intersect_range_step.rb +17 -0
- data/lib/zermelo/filters/steps/intersect_step.rb +17 -0
- data/lib/zermelo/filters/steps/limit_step.rb +17 -0
- data/lib/zermelo/filters/steps/offset_step.rb +17 -0
- data/lib/zermelo/filters/steps/sort_step.rb +17 -0
- data/lib/zermelo/filters/steps/union_range_step.rb +17 -0
- data/lib/zermelo/filters/steps/union_step.rb +17 -0
- data/lib/zermelo/locks/no_lock.rb +16 -0
- data/lib/zermelo/locks/redis_lock.rb +221 -0
- data/lib/zermelo/records/base.rb +62 -0
- data/lib/zermelo/records/class_methods.rb +127 -0
- data/lib/zermelo/records/collection.rb +14 -0
- data/lib/zermelo/records/errors.rb +24 -0
- data/lib/zermelo/records/influxdb_record.rb +35 -0
- data/lib/zermelo/records/instance_methods.rb +224 -0
- data/lib/zermelo/records/key.rb +19 -0
- data/lib/zermelo/records/redis_record.rb +27 -0
- data/lib/zermelo/records/type_validator.rb +20 -0
- data/lib/zermelo/version.rb +3 -0
- data/lib/zermelo.rb +102 -0
- data/spec/lib/zermelo/associations/belongs_to_spec.rb +6 -0
- data/spec/lib/zermelo/associations/has_many_spec.rb +6 -0
- data/spec/lib/zermelo/associations/has_one_spec.rb +6 -0
- data/spec/lib/zermelo/associations/has_sorted_set.spec.rb +6 -0
- data/spec/lib/zermelo/associations/index_spec.rb +6 -0
- data/spec/lib/zermelo/associations/unique_index_spec.rb +6 -0
- data/spec/lib/zermelo/backends/influxdb_backend_spec.rb +0 -0
- data/spec/lib/zermelo/backends/moneta_backend_spec.rb +0 -0
- data/spec/lib/zermelo/filters/influxdb_filter_spec.rb +0 -0
- data/spec/lib/zermelo/filters/redis_filter_spec.rb +0 -0
- data/spec/lib/zermelo/locks/redis_lock_spec.rb +170 -0
- data/spec/lib/zermelo/records/influxdb_record_spec.rb +258 -0
- data/spec/lib/zermelo/records/key_spec.rb +6 -0
- data/spec/lib/zermelo/records/redis_record_spec.rb +1426 -0
- data/spec/lib/zermelo/records/type_validator_spec.rb +6 -0
- data/spec/lib/zermelo/version_spec.rb +6 -0
- data/spec/lib/zermelo_spec.rb +6 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/profile_all_formatter.rb +44 -0
- data/spec/support/uncolored_doc_formatter.rb +74 -0
- data/zermelo.gemspec +30 -0
- metadata +174 -0
@@ -0,0 +1,258 @@
|
|
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::InfluxDBExampleChild'
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class InfluxDBExampleChild
|
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
|
+
end
|
31
|
+
|
32
|
+
def create_example(attrs = {})
|
33
|
+
Zermelo.influxdb.write_point("influx_db_example/#{attrs[:id]}", attrs)
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:influxdb) { Zermelo.influxdb }
|
37
|
+
|
38
|
+
it "is invalid without a name" do
|
39
|
+
example = Zermelo::InfluxDBExample.new(:id => '1',
|
40
|
+
:email => 'jsmith@example.com', :active => true)
|
41
|
+
expect(example).not_to be_valid
|
42
|
+
|
43
|
+
errs = example.errors
|
44
|
+
expect(errs).not_to be_nil
|
45
|
+
expect(errs[:name]).to eq(["can't be blank"])
|
46
|
+
end
|
47
|
+
|
48
|
+
it "adds a record's attributes to influxdb" do
|
49
|
+
begin
|
50
|
+
data = Zermelo.influxdb.query("select * from /influx_db_example\\/1/")['influx_db_example/1']
|
51
|
+
expect(data).to be_nil
|
52
|
+
rescue InfluxDB::Error => ide
|
53
|
+
# only happens occasionally, with an empty time series by that name
|
54
|
+
raise unless /^Couldn't look up columns$/ === ide.message
|
55
|
+
end
|
56
|
+
|
57
|
+
example = Zermelo::InfluxDBExample.new(:id => '1', :name => 'John Smith',
|
58
|
+
:email => 'jsmith@example.com', :active => true)
|
59
|
+
expect(example).to be_valid
|
60
|
+
expect(example.save).to be_truthy
|
61
|
+
|
62
|
+
data = Zermelo.influxdb.query("select * from /influx_db_example\\/1/")['influx_db_example/1']
|
63
|
+
expect(data).to be_an(Array)
|
64
|
+
expect(data.size).to eql(1)
|
65
|
+
record = data.first
|
66
|
+
expect(record).to be_a(Hash)
|
67
|
+
# FIXME boolean is stringified as redis needs it to be like that --
|
68
|
+
# should probably make this backend-dependent
|
69
|
+
expect(record).to include("name"=>"John Smith",
|
70
|
+
"email"=>"jsmith@example.com", "active"=>"true", "id"=>"1")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "finds a record by id in influxdb" do
|
74
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
75
|
+
:active => 'true')
|
76
|
+
|
77
|
+
example = Zermelo::InfluxDBExample.find_by_id('1')
|
78
|
+
expect(example).not_to be_nil
|
79
|
+
|
80
|
+
expect(example).to respond_to(:name)
|
81
|
+
expect(example.name).to eql('Jane Doe')
|
82
|
+
expect(example).to respond_to(:email)
|
83
|
+
expect(example.email).to eql('jdoe@example.com')
|
84
|
+
expect(example).to respond_to(:active)
|
85
|
+
expect(example.active).to be true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "can update a value in influxdb" do
|
89
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
90
|
+
:active => 'true')
|
91
|
+
|
92
|
+
example = Zermelo::InfluxDBExample.find_by_id('1')
|
93
|
+
expect(example).not_to be_nil
|
94
|
+
|
95
|
+
example.name = 'John Smith'
|
96
|
+
example.save
|
97
|
+
|
98
|
+
other_example = Zermelo::InfluxDBExample.find_by_id('1')
|
99
|
+
expect(other_example).not_to be_nil
|
100
|
+
expect(other_example.name).to eq('John Smith')
|
101
|
+
end
|
102
|
+
|
103
|
+
it "destroys a single record from influxdb" do
|
104
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
105
|
+
:active => 'true')
|
106
|
+
|
107
|
+
example = Zermelo::InfluxDBExample.find_by_id('1')
|
108
|
+
example.destroy
|
109
|
+
example_chk = Zermelo::InfluxDBExample.find_by_id('1')
|
110
|
+
expect(example_chk).to be_nil
|
111
|
+
end
|
112
|
+
|
113
|
+
it "resets changed state on refresh" do
|
114
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
115
|
+
:active => 'true')
|
116
|
+
example = Zermelo::InfluxDBExample.find_by_id('1')
|
117
|
+
|
118
|
+
example.name = "King Henry VIII"
|
119
|
+
expect(example.changed).to include('name')
|
120
|
+
expect(example.changes).to eq({'name' => ['Jane Doe', 'King Henry VIII']})
|
121
|
+
|
122
|
+
example.refresh
|
123
|
+
expect(example.changed).to be_empty
|
124
|
+
expect(example.changes).to be_empty
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'filters' do
|
128
|
+
|
129
|
+
it "returns all record ids" do
|
130
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
131
|
+
:active => 'true')
|
132
|
+
create_example(:id => '2', :name => 'John Smith',
|
133
|
+
:email => 'jsmith@example.com', :active => 'false')
|
134
|
+
|
135
|
+
examples = Zermelo::InfluxDBExample.ids
|
136
|
+
expect(examples).not_to be_nil
|
137
|
+
expect(examples).to be_an(Array)
|
138
|
+
expect(examples.size).to eq(2)
|
139
|
+
expect(examples).to contain_exactly('2', '1')
|
140
|
+
end
|
141
|
+
|
142
|
+
it "returns a count of records" do
|
143
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
144
|
+
:active => 'true')
|
145
|
+
create_example(:id => '2', :name => 'John Smith',
|
146
|
+
:email => 'jsmith@example.com', :active => 'false')
|
147
|
+
|
148
|
+
example_count = Zermelo::InfluxDBExample.count
|
149
|
+
expect(example_count).not_to be_nil
|
150
|
+
expect(example_count).to be_an(Integer)
|
151
|
+
expect(example_count).to eq(2)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "returns all records" do
|
155
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
156
|
+
:active => 'true')
|
157
|
+
create_example(:id => '2', :name => 'John Smith',
|
158
|
+
:email => 'jsmith@example.com', :active => 'false')
|
159
|
+
|
160
|
+
examples = Zermelo::InfluxDBExample.all
|
161
|
+
expect(examples).not_to be_nil
|
162
|
+
expect(examples).to be_an(Array)
|
163
|
+
expect(examples.size).to eq(2)
|
164
|
+
expect(examples.map(&:id)).to contain_exactly('2', '1')
|
165
|
+
end
|
166
|
+
|
167
|
+
it "filters all class records by attribute values" do
|
168
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
169
|
+
:active => 'true')
|
170
|
+
create_example(:id => '2', :name => 'John Smith',
|
171
|
+
:email => 'jsmith@example.com', :active => 'false')
|
172
|
+
|
173
|
+
example = Zermelo::InfluxDBExample.intersect(:active => true).all
|
174
|
+
expect(example).not_to be_nil
|
175
|
+
expect(example).to be_an(Array)
|
176
|
+
expect(example.size).to eq(1)
|
177
|
+
expect(example.map(&:id)).to eq(['1'])
|
178
|
+
end
|
179
|
+
|
180
|
+
it "chains two intersect filters together" do
|
181
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
182
|
+
:active => 'true')
|
183
|
+
create_example(:id => '2', :name => 'John Smith',
|
184
|
+
:email => 'jsmith@example.com', :active => 'false')
|
185
|
+
create_example(:id => '3', :name => 'Fred Bloggs',
|
186
|
+
:email => 'fbloggs@example.com', :active => 'true')
|
187
|
+
|
188
|
+
example = Zermelo::InfluxDBExample.intersect(:active => true).
|
189
|
+
intersect(:name => 'Jane Doe').all
|
190
|
+
expect(example).not_to be_nil
|
191
|
+
expect(example).to be_an(Array)
|
192
|
+
expect(example.size).to eq(1)
|
193
|
+
expect(example.map(&:id)).to eq(['1'])
|
194
|
+
end
|
195
|
+
|
196
|
+
it "chains an intersect and a union filter together" do
|
197
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
198
|
+
:active => 'true')
|
199
|
+
create_example(:id => '2', :name => 'John Smith',
|
200
|
+
:email => 'jsmith@example.com', :active => 'false')
|
201
|
+
create_example(:id => '3', :name => 'Fred Bloggs',
|
202
|
+
:email => 'fbloggs@example.com', :active => 'false')
|
203
|
+
|
204
|
+
example = Zermelo::InfluxDBExample.intersect(:active => true).union(:name => 'Fred Bloggs').all
|
205
|
+
expect(example).not_to be_nil
|
206
|
+
expect(example).to be_an(Array)
|
207
|
+
expect(example.size).to eq(2)
|
208
|
+
expect(example.map(&:id)).to contain_exactly('3', '1')
|
209
|
+
end
|
210
|
+
|
211
|
+
it "chains an intersect and a diff filter together" do
|
212
|
+
create_example(:id => '1', :name => 'Jane Doe', :email => 'jdoe@example.com',
|
213
|
+
:active => 'true')
|
214
|
+
create_example(:id => '2', :name => 'John Smith',
|
215
|
+
:email => 'jsmith@example.com', :active => 'false')
|
216
|
+
create_example(:id => '3', :name => 'Fred Bloggs',
|
217
|
+
:email => 'fbloggs@example.com', :active => 'false')
|
218
|
+
|
219
|
+
example = Zermelo::InfluxDBExample.intersect(:active => false).diff(:name => 'Fred Bloggs').all
|
220
|
+
expect(example).not_to be_nil
|
221
|
+
expect(example).to be_an(Array)
|
222
|
+
expect(example.size).to eq(1)
|
223
|
+
expect(example.map(&:id)).to eq(['2'])
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
context 'has_many association' do
|
229
|
+
|
230
|
+
# def create_child(attrs = {})
|
231
|
+
# Zermelo.influxdb.write_point('influx_db_example_child', attrs)
|
232
|
+
# end
|
233
|
+
|
234
|
+
it "sets a parent/child has_many relationship between two records in influxdb" do
|
235
|
+
create_example(:id => '8', :name => 'John Jones',
|
236
|
+
:email => 'jjones@example.com', :active => 'true')
|
237
|
+
|
238
|
+
child = Zermelo::InfluxDBExampleChild.new(:id => '3', :name => 'Abel Tasman')
|
239
|
+
expect(child.save).to be_truthy
|
240
|
+
|
241
|
+
example = Zermelo::InfluxDBExample.find_by_id('8')
|
242
|
+
|
243
|
+
children = example.children.all
|
244
|
+
|
245
|
+
expect(children).to be_an(Array)
|
246
|
+
expect(children).to be_empty
|
247
|
+
|
248
|
+
example.children << child
|
249
|
+
|
250
|
+
children = example.children.all
|
251
|
+
|
252
|
+
expect(children).to be_an(Array)
|
253
|
+
expect(children.size).to eq(1)
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|