json_record 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.
- data/MIT_LICENSE +20 -0
- data/README.rdoc +88 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/json_record.gemspec +72 -0
- data/lib/json_record/attribute_methods.rb +55 -0
- data/lib/json_record/embedded_document.rb +155 -0
- data/lib/json_record/embedded_document_array.rb +54 -0
- data/lib/json_record/field_definition.rb +87 -0
- data/lib/json_record/json_field.rb +59 -0
- data/lib/json_record/schema.rb +128 -0
- data/lib/json_record/serialized.rb +106 -0
- data/lib/json_record.rb +20 -0
- data/spec/embedded_document_array_spec.rb +64 -0
- data/spec/embedded_document_spec.rb +65 -0
- data/spec/field_definition_spec.rb +29 -0
- data/spec/serialized_spec.rb +430 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/test_models.rb +70 -0
- metadata +111 -0
@@ -0,0 +1,430 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
describe JsonRecord::Serialized do
|
4
|
+
before(:all) do
|
5
|
+
JsonRecord::Test.create_tables
|
6
|
+
end
|
7
|
+
|
8
|
+
after(:all) do
|
9
|
+
JsonRecord::Test.drop_tables
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have accessors for json attributes" do
|
13
|
+
model = JsonRecord::Test::Model.new
|
14
|
+
model.name.should == nil
|
15
|
+
model.name = "test"
|
16
|
+
model.name.should == "test"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should convert blank values to nil" do
|
20
|
+
model = JsonRecord::Test::Model.new
|
21
|
+
model.name = ""
|
22
|
+
model.name.should == nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should convert values to strings" do
|
26
|
+
model = JsonRecord::Test::Model.new
|
27
|
+
model.name = 1
|
28
|
+
model.name.should == "1"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should convert values to integers" do
|
32
|
+
model = JsonRecord::Test::Model.new
|
33
|
+
model.value = "1"
|
34
|
+
model.value.should == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should convert values to floats" do
|
38
|
+
model = JsonRecord::Test::Model.new
|
39
|
+
model.price = "1.2"
|
40
|
+
model.price.should == 1.2
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should convert values to dates" do
|
44
|
+
model = JsonRecord::Test::Model.new
|
45
|
+
model.when = "2010-01-25"
|
46
|
+
model.when.should == Date.civil(2010, 1, 25)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should convert values to times" do
|
50
|
+
model = JsonRecord::Test::Model.new
|
51
|
+
model.verified_at = "2010-01-25T12:00:15-6:00"
|
52
|
+
model.verified_at.should == Time.parse("2010-01-25T12:00:15-6:00").utc
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should convert values to datetimes" do
|
56
|
+
model = JsonRecord::Test::Model.new
|
57
|
+
model.viewed_at = "2010-01-25T12:00:15-6:00"
|
58
|
+
model.viewed_at.should == Time.parse("2010-01-25T12:00:15-6:00").utc
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should convert values to booleans" do
|
62
|
+
model = JsonRecord::Test::Model.new
|
63
|
+
model.verified = "true"
|
64
|
+
model.verified.should == true
|
65
|
+
model.verified = "false"
|
66
|
+
model.verified.should == false
|
67
|
+
model.verified = "1"
|
68
|
+
model.verified?.should == true
|
69
|
+
model.verified = "0"
|
70
|
+
model.verified?.should == false
|
71
|
+
model.verified = 1
|
72
|
+
model.verified?.should == true
|
73
|
+
model.verified = 0
|
74
|
+
model.verified?.should == false
|
75
|
+
model.verified = true
|
76
|
+
model.verified?.should == true
|
77
|
+
model.verified = nil
|
78
|
+
model.verified?.should == false
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should convert values to array" do
|
82
|
+
model = JsonRecord::Test::Model.new
|
83
|
+
model.strings = "a"
|
84
|
+
model.strings.should == ["a"]
|
85
|
+
model.strings = ["a", "b"]
|
86
|
+
model.strings.should == ["a", "b"]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should convert a hash to an embedded document" do
|
90
|
+
model = JsonRecord::Test::Model.new
|
91
|
+
model.primary_trait = {:name => "thing", :value => "stuff"}
|
92
|
+
model.primary_trait.name.should == "thing"
|
93
|
+
model.primary_trait.value.should == "stuff"
|
94
|
+
model.primary_trait.attributes.should == {"name" => "thing", "value" => "stuff"}
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not convert values that are already of the right class" do
|
98
|
+
model = JsonRecord::Test::Model.new
|
99
|
+
model.map = {:name => "thing", :value => "stuff"}
|
100
|
+
model.map.should == {:name => "thing", :value => "stuff"}
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should leave a value unconverted if it can't be converted" do
|
104
|
+
model = JsonRecord::Test::Model.new
|
105
|
+
model.value = "foo"
|
106
|
+
model.value.should == "foo"
|
107
|
+
model.price = "expensive"
|
108
|
+
model.price.should == "expensive"
|
109
|
+
model.when = "now"
|
110
|
+
model.when.should == "now"
|
111
|
+
model.verified_at = "2001-100-100"
|
112
|
+
model.verified_at.should == "2001-100-100"
|
113
|
+
model.viewed_at = "the year 2000"
|
114
|
+
model.viewed_at.should == "the year 2000"
|
115
|
+
lambda{model.primary_trait = "stuff"}.should raise_error(ArgumentError)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should mix the json attributes into the regular attribute minus the json field itself" do
|
119
|
+
model = JsonRecord::Test::Model.new(:string_field => "test")
|
120
|
+
model.name = "test name"
|
121
|
+
model.value = 1
|
122
|
+
attrs = model.attributes
|
123
|
+
attrs["string_field"].should == "test"
|
124
|
+
attrs["name"].should == "test name"
|
125
|
+
attrs["value"].should == 1
|
126
|
+
attrs.should_not include("json")
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should use default values if a value has not been set" do
|
130
|
+
model = JsonRecord::Test::Model.new
|
131
|
+
model.value.should == 0
|
132
|
+
model.value = nil
|
133
|
+
model.value.should == 0
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should initialize json attributes with blank values" do
|
137
|
+
JsonRecord::Test::Model.new.attributes.should == {
|
138
|
+
"name"=>nil,
|
139
|
+
"price"=>nil,
|
140
|
+
"string_field"=>nil,
|
141
|
+
"verified_at"=>nil,
|
142
|
+
"viewed_at"=>nil,
|
143
|
+
"field_1"=>nil,
|
144
|
+
"field_2"=>nil,
|
145
|
+
"field_3"=>nil,
|
146
|
+
"field_4"=>nil,
|
147
|
+
"field_5"=>nil,
|
148
|
+
"traits"=>[],
|
149
|
+
"value"=>0,
|
150
|
+
"strings"=>[],
|
151
|
+
"map"=>{},
|
152
|
+
"verified"=>nil,
|
153
|
+
"when"=>nil,
|
154
|
+
"primary_trait"=>nil
|
155
|
+
}
|
156
|
+
JsonRecord::Test::Model.new.attributes["traits"].should be_a(JsonRecord::EmbeddedDocumentArray)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should make default values automatically for arrays and hashes" do
|
160
|
+
model_1 = JsonRecord::Test::Model.new
|
161
|
+
model_1.strings << "val"
|
162
|
+
model_1.strings.should == ["val"]
|
163
|
+
model_1.map["val"] = 1
|
164
|
+
model_1.map.should == {"val" => 1}
|
165
|
+
model_2 = JsonRecord::Test::Model.new
|
166
|
+
model_2.strings << "val2"
|
167
|
+
model_2.strings.should == ["val2"]
|
168
|
+
model_2.map["val2"] = 2
|
169
|
+
model_2.map.should == {"val2" => 2}
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should allow mass assignment of json attributes" do
|
173
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :string_field => "test string_field", :price => "1")
|
174
|
+
model.name.should == "test name"
|
175
|
+
model.string_field.should == "test string_field"
|
176
|
+
model.price.should == 1.0
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should deserialize JSON in a json field into the attributes" do
|
180
|
+
model = JsonRecord::Test::Model.new(:json => '{"name": "test name", "value": 1}')
|
181
|
+
model.name.should == "test name"
|
182
|
+
model.value.should == 1
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should reserialize json attributes into a JSON field" do
|
186
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :value => 1)
|
187
|
+
model.save!
|
188
|
+
model = JsonRecord::Test::Model.find(model.id)
|
189
|
+
ActiveSupport::JSON.decode(model.json).should == {"name" => "test name", "value" => 1}
|
190
|
+
model.value = 2
|
191
|
+
model.save!
|
192
|
+
model = JsonRecord::Test::Model.find(model.id)
|
193
|
+
ActiveSupport::JSON.decode(model.json).should == {"name" => "test name", "value" => 2}
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should keep undefined keys found in the JSON field" do
|
197
|
+
model = JsonRecord::Test::Model.new(:json => '{"name": "test name", "value": 1, "unknown": "my value", "other stuff": {"value": 2}, "primary_trait": {"name": "n1", "stuff": true}}')
|
198
|
+
model.save!
|
199
|
+
model.value = 2
|
200
|
+
model.primary_trait.value = "beans"
|
201
|
+
ActiveSupport::JSON.decode(model.json).should == {"name" => "test name", "value" => 1, "unknown" => "my value", "other stuff" => {"value" => 2}, "primary_trait" => {"name" => "n1", "stuff" => true, "sub_traits" => []}}
|
202
|
+
model = JsonRecord::Test::Model.find(model.id)
|
203
|
+
ActiveSupport::JSON.decode(model.json).should == {"name" => "test name", "value" => 1, "unknown" => "my value", "other stuff" => {"value" => 2}, "primary_trait" => {"name" => "n1", "stuff" => true, "sub_traits" => []}}
|
204
|
+
model.attributes.should_not include("other stuff")
|
205
|
+
model.should_not respond_to(:other_stuff)
|
206
|
+
model.primary_trait.attributes.should_not include("stuff")
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should allow multiple JSON fields" do
|
210
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :value => 1, :field_1 => "one")
|
211
|
+
model.save!
|
212
|
+
model = JsonRecord::Test::Model.find(model.id)
|
213
|
+
model.name.should == "test name"
|
214
|
+
model.field_1.should == "one"
|
215
|
+
ActiveSupport::JSON.decode(model.json).should == {"name" => "test name", "value" => 1}
|
216
|
+
ActiveSupport::JSON.decode(Zlib::Inflate.inflate(model.compressed_json)).should == {"field_1" => "one"}
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should have json attributes inherited by subclasses" do
|
220
|
+
model = JsonRecord::Test::Model.new(:name => "test name")
|
221
|
+
model.respond_to?(:another_field).should == false
|
222
|
+
sub_model = JsonRecord::Test::SubModel.new(:name => "test name", :another_field => "woo")
|
223
|
+
sub_model.another_field.should == "woo"
|
224
|
+
sub_model.save!
|
225
|
+
sub_model = JsonRecord::Test::SubModel.find(sub_model.id)
|
226
|
+
sub_model.another_field.should == "woo"
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should track changes on json attributes" do
|
230
|
+
model = JsonRecord::Test::Model.create!(:name => "test name")
|
231
|
+
model.changes.should == {}
|
232
|
+
model.name = "new name"
|
233
|
+
model.value = 1
|
234
|
+
model.changes.should == {"name" => ["test name", "new name"], "value" => [0, 1]}
|
235
|
+
model.name_changed?.should == true
|
236
|
+
model.name_was.should == "test name"
|
237
|
+
model.name_change.should == ["test name", "new name"]
|
238
|
+
model.name = "test name"
|
239
|
+
model.changes.should == {"value" => [0, 1]}
|
240
|
+
model.name_changed?.should == false
|
241
|
+
model.name_was.should == "test name"
|
242
|
+
model.name_change.should == nil
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should validate the presence of a json attribute" do
|
246
|
+
model = JsonRecord::Test::Model.new
|
247
|
+
model.valid?.should == false
|
248
|
+
model.errors.on(:name).should_not == nil
|
249
|
+
model.name = "woo"
|
250
|
+
model.valid?.should == true
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should validate the length of a json attribute" do
|
254
|
+
model = JsonRecord::Test::Model.new(:name => "this name value is way too long", :field_4 => "a", :field_5 => "b")
|
255
|
+
model.valid?.should == false
|
256
|
+
model.errors.on(:name).should_not == nil
|
257
|
+
model.errors.on(:field_4).should_not == nil
|
258
|
+
model.errors.on(:field_5).should_not == nil
|
259
|
+
model.name = "shorter name"
|
260
|
+
model.field_4 = "a much longer name that won't fit"
|
261
|
+
model.field_5 = "a much longer name that will fit because it is OK"
|
262
|
+
model.valid?.should == false
|
263
|
+
model.errors.on(:name).should == nil
|
264
|
+
model.errors.on(:field_4).should_not == nil
|
265
|
+
model.errors.on(:field_5).should == nil
|
266
|
+
model.field_4 = "just right"
|
267
|
+
model.valid?.should == true
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should validate the type of a json attribute" do
|
271
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :value => "purple", :price => "free", :when => "2010-40-52", :verified_at => "2010-40-50T00:00:00", :viewed_at => "2010-02-01T00:90:00")
|
272
|
+
model.valid?.should == false
|
273
|
+
model.errors.on(:value).should_not == nil
|
274
|
+
model.errors.on(:price).should_not == nil
|
275
|
+
model.errors.on(:when).should_not == nil
|
276
|
+
model.errors.on(:verified_at).should_not == nil
|
277
|
+
model.errors.on(:viewed_at).should_not == nil
|
278
|
+
model.value = "1"
|
279
|
+
model.price = "100"
|
280
|
+
model.when = "2010-02-01"
|
281
|
+
model.verified_at = Time.now.to_s
|
282
|
+
model.viewed_at = DateTime.now.to_s
|
283
|
+
model.valid?.should == true
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should validate that a json attribute is in a range" do
|
287
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :field_3 => "Z")
|
288
|
+
model.valid?.should == false
|
289
|
+
model.errors.on(:field_3).should_not == nil
|
290
|
+
model.field_3 = "B"
|
291
|
+
model.valid?.should == true
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should validate the format of a json attribute" do
|
295
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :field_2 => "ABC")
|
296
|
+
model.valid?.should == false
|
297
|
+
model.errors.on(:field_2).should_not == nil
|
298
|
+
model.field_2 = "abc"
|
299
|
+
model.valid?.should == true
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should reload the json attributes when the record is reloaded" do
|
303
|
+
model = JsonRecord::Test::Model.new(:name => "test name", :field_1 => "ABC")
|
304
|
+
model.save!
|
305
|
+
model.name = "new name"
|
306
|
+
model.field_1 = "abc"
|
307
|
+
model.name.should == "new name"
|
308
|
+
model.field_1.should == "abc"
|
309
|
+
model.reload
|
310
|
+
model.name.should == "test name"
|
311
|
+
model.field_1.should == "ABC"
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should compress data if it is stored in a binary column" do
|
315
|
+
model = JsonRecord::Test::Model.new(:name => "test", :field_1 => "one", :field_2 => "two")
|
316
|
+
model.save!
|
317
|
+
model = JsonRecord::Test::Model.find(model.id)
|
318
|
+
model.field_1.should == "one"
|
319
|
+
model.field_2.should == "two"
|
320
|
+
ActiveSupport::JSON.decode(Zlib::Inflate.inflate(model.compressed_json)).should == {"field_1" => "one", "field_2" => "two"}
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should handle embedded documents" do
|
324
|
+
model = JsonRecord::Test::Model.new(:name => "test", :primary_trait => {:name => "primary", :value => "primary value"})
|
325
|
+
model.primary_trait.name.should == "primary"
|
326
|
+
model.primary_trait.value.should == "primary value"
|
327
|
+
model.primary_trait.parent.should == model
|
328
|
+
|
329
|
+
model.save!
|
330
|
+
model = JsonRecord::Test::Model.find(model.id)
|
331
|
+
model.primary_trait.name.should == "primary"
|
332
|
+
model.primary_trait.value.should == "primary value"
|
333
|
+
model.primary_trait.parent.should == model
|
334
|
+
|
335
|
+
model.primary_trait = JsonRecord::Test::Trait.new(:name => "new", :value => "val")
|
336
|
+
model.save!
|
337
|
+
model = JsonRecord::Test::Model.find(model.id)
|
338
|
+
model.primary_trait.name.should == "new"
|
339
|
+
model.primary_trait.value.should == "val"
|
340
|
+
model.primary_trait.parent.should == model
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should handle many embedded documents" do
|
344
|
+
model = JsonRecord::Test::Model.new(:name => "test", :traits => [{:name => "n1", :value => "v1"}, {:name => "n2", :value => "v2"}])
|
345
|
+
model.traits.build(:name => "n3", :value => "v3")
|
346
|
+
model.traits.build(JsonRecord::Test::Trait.new(:name => "n4", :value => "v4"))
|
347
|
+
model.traits << {"name" => "n5", "value" => "v5"}
|
348
|
+
model.traits << JsonRecord::Test::Trait.new("name" => "n6", "value" => "v6")
|
349
|
+
model.traits.concat([{"name" => "n7", "value" => "v7"}, {:name => "n8", :value => "v8"}, JsonRecord::Test::Trait.new("name" => "n9", "value" => "v9")])
|
350
|
+
model.traits.collect{|t| [t.name, t.value]}.should == [["n1", "v1"], ["n2", "v2"], ["n3", "v3"], ["n4", "v4"], ["n5", "v5"], ["n6", "v6"], ["n7", "v7"], ["n8", "v8"], ["n9", "v9"]]
|
351
|
+
model.traits.collect{|t| t.parent}.uniq.should == [model]
|
352
|
+
|
353
|
+
model.save!
|
354
|
+
model = JsonRecord::Test::Model.find(model.id)
|
355
|
+
model.traits.collect{|t| [t.name, t.value]}.should == [["n1", "v1"], ["n2", "v2"], ["n3", "v3"], ["n4", "v4"], ["n5", "v5"], ["n6", "v6"], ["n7", "v7"], ["n8", "v8"], ["n9", "v9"]]
|
356
|
+
model.traits.collect{|t| t.parent}.uniq.should == [model]
|
357
|
+
|
358
|
+
model.traits.slice!(0)
|
359
|
+
model.traits.pop
|
360
|
+
model.traits = model.traits.reverse
|
361
|
+
model.traits[1].name = "name7"
|
362
|
+
model.traits[1].value = "value7"
|
363
|
+
model.save!
|
364
|
+
model = JsonRecord::Test::Model.find(model.id)
|
365
|
+
model.traits.collect{|t| [t.name, t.value]}.should == [["n8", "v8"], ["name7", "value7"], ["n6", "v6"], ["n5", "v5"], ["n4", "v4"], ["n3", "v3"], ["n2", "v2"]]
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should handle nested embedded documents" do
|
369
|
+
model = JsonRecord::Test::Model.new(:name => "test")
|
370
|
+
trait = model.traits.build(:name => "n1", :value => "v1")
|
371
|
+
subtrait = trait.sub_traits.build(:name => "s1", :value => "v1")
|
372
|
+
model.traits.should == [trait]
|
373
|
+
model.traits.first.sub_traits.should == [subtrait]
|
374
|
+
model.save!
|
375
|
+
model = JsonRecord::Test::Model.find(model.id)
|
376
|
+
end
|
377
|
+
|
378
|
+
it "should be able to set a many key with the values in a hash" do
|
379
|
+
model = JsonRecord::Test::Model.new(:name => "test")
|
380
|
+
model.traits = {"first" => {:name => "n1", :value => "v1"}, "second" => {:name => "n2", :value => "v2"}}
|
381
|
+
model.traits.size.should == 2
|
382
|
+
model.traits.collect{|t| t.name}.sort.should == ["n1", "n2"]
|
383
|
+
end
|
384
|
+
|
385
|
+
it "should get the json field definition for a field" do
|
386
|
+
JsonRecord::Test::Model.json_field_definition(:value).name.should == "value"
|
387
|
+
JsonRecord::Test::Model.json_field_definition("value").name.should == "value"
|
388
|
+
JsonRecord::Test::Model.json_field_definition("nothing").should == nil
|
389
|
+
end
|
390
|
+
|
391
|
+
it "should validate uniqueness of embedded documents" do
|
392
|
+
model = JsonRecord::Test::Model.new(:name => "test", :traits => [{:name => "n1", :value => "v1"}, {:name => "n1", :value => "v2"}])
|
393
|
+
model.valid?.should == false
|
394
|
+
model.errors.on(:traits).should_not == nil
|
395
|
+
model.traits.first.errors.on(:name).should == nil
|
396
|
+
model.traits.last.errors.on(:name).should_not == nil
|
397
|
+
|
398
|
+
model.traits.last.name = "n2"
|
399
|
+
model.valid?.should == true
|
400
|
+
model.errors.on(:traits).should == nil
|
401
|
+
model.traits.first.errors.on(:name).should == nil
|
402
|
+
model.traits.last.errors.on(:name).should == nil
|
403
|
+
end
|
404
|
+
|
405
|
+
it "should perform validations on embedded documents" do
|
406
|
+
model = JsonRecord::Test::Model.new(:name => "test")
|
407
|
+
model.primary_trait = {:name => "", :value => "v2"}
|
408
|
+
trait = model.traits.build(:value => "v1")
|
409
|
+
subtrait = trait.sub_traits.build(:name => "s1", :count => "plaid")
|
410
|
+
model.valid?.should == false
|
411
|
+
model.errors.on(:primary_trait).should_not == nil
|
412
|
+
model.errors.on(:traits).should_not == nil
|
413
|
+
model.primary_trait.errors.on(:name).should_not == nil
|
414
|
+
trait.errors.on(:name).should_not == nil
|
415
|
+
trait.errors.on(:sub_traits).should_not == nil
|
416
|
+
subtrait.errors.on(:count).should_not == nil
|
417
|
+
|
418
|
+
model.primary_trait.name = "p1"
|
419
|
+
trait.name = "n1"
|
420
|
+
subtrait.count = 1
|
421
|
+
model.valid?.should == true
|
422
|
+
model.errors.on(:primary_trait).should == nil
|
423
|
+
model.errors.on(:traits).should == nil
|
424
|
+
model.primary_trait.errors.on(:name).should == nil
|
425
|
+
trait.errors.on(:name).should == nil
|
426
|
+
trait.errors.on(:sub_traits).should == nil
|
427
|
+
subtrait.errors.on(:count).should == nil
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
active_record_version = ENV["ACTIVE_RECORD_VERSION"] || [">= 2.2.2", "< 3.0"]
|
4
|
+
active_record_version = [active_record_version] unless active_record_version.is_a?(Array)
|
5
|
+
gem 'activerecord', *active_record_version
|
6
|
+
|
7
|
+
require 'spec'
|
8
|
+
require 'active_record'
|
9
|
+
puts "Testing Against ActiveRecord #{ActiveRecord::VERSION::STRING}" if defined?(ActiveRecord::VERSION)
|
10
|
+
ActiveRecord.load_all! if ActiveRecord.respond_to?(:load_all!)
|
11
|
+
|
12
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'json_record'))
|
13
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_models'))
|
data/spec/test_models.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module JsonRecord
|
2
|
+
module Test
|
3
|
+
def self.create_tables
|
4
|
+
db_dir = File.expand_path(File.join(__FILE__, '..', 'tmp'))
|
5
|
+
Dir.mkdir(db_dir) unless File.exist?(db_dir)
|
6
|
+
db = File.join(db_dir, 'test_JsonRecord.sqlite3')
|
7
|
+
Model.establish_connection("adapter" => "sqlite3", "database" => db)
|
8
|
+
|
9
|
+
Model.connection.create_table(:models) do |t|
|
10
|
+
t.text :json
|
11
|
+
t.binary :compressed_json
|
12
|
+
t.string :string_field
|
13
|
+
end unless Model.table_exists?
|
14
|
+
|
15
|
+
SubModel.connection.create_table(:sub_models) do |t|
|
16
|
+
t.text :json
|
17
|
+
t.binary :compressed_json
|
18
|
+
t.string :string_field
|
19
|
+
end unless SubModel.table_exists?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.drop_tables
|
23
|
+
db_dir = File.expand_path(File.join(__FILE__, '..', 'tmp'))
|
24
|
+
db = File.join(db_dir, 'test_JsonRecord.sqlite3')
|
25
|
+
Model.connection.disconnect!
|
26
|
+
File.delete(db) if File.exist?(db)
|
27
|
+
Dir.delete(db_dir) if File.exist?(db_dir) and Dir.entries(db_dir).reject{|f| f.match(/^\.+$/)}.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
class Trait < JsonRecord::EmbeddedDocument
|
31
|
+
key :name, :required => true
|
32
|
+
key :value
|
33
|
+
key :count, Integer
|
34
|
+
many :sub_traits, Trait, :unique => [:name, :value]
|
35
|
+
end
|
36
|
+
|
37
|
+
class Model < ActiveRecord::Base
|
38
|
+
include JsonRecord::Serialized
|
39
|
+
serialize_to_json(:json) do |schema|
|
40
|
+
schema.key :name, String, :required => true, :length => 15
|
41
|
+
schema.key :value, Integer, :default => 0
|
42
|
+
schema.key :price, Float
|
43
|
+
schema.key :verified, Boolean
|
44
|
+
schema.key :when, Date
|
45
|
+
schema.key :verified_at, Time
|
46
|
+
schema.key :viewed_at, DateTime
|
47
|
+
schema.key :strings, Array
|
48
|
+
schema.key :map, Hash
|
49
|
+
schema.key :primary_trait, Trait
|
50
|
+
schema.many :traits, Trait, :unique => :name
|
51
|
+
end
|
52
|
+
|
53
|
+
serialize_to_json(:compressed_json) do |schema|
|
54
|
+
schema.key :field_1
|
55
|
+
schema.key :field_2, :format => /^[a-z]+$/
|
56
|
+
schema.key :field_3, :in => ("A".."M")
|
57
|
+
schema.key :field_4, :length => (4..15)
|
58
|
+
schema.key :field_5, :length => {:minimum => 5}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class SubModel < Model
|
63
|
+
set_table_name :sub_models
|
64
|
+
|
65
|
+
serialize_to_json(:json) do |schema|
|
66
|
+
schema.key :another_field
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json_record
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Durand
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-07 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.2.2
|
24
|
+
- - <
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: "3.0"
|
27
|
+
version:
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
type: :development
|
31
|
+
version_requirement:
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.2.9
|
37
|
+
version:
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: jeweler
|
40
|
+
type: :development
|
41
|
+
version_requirement:
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
description:
|
49
|
+
email: brian@embellishedvisions.com
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- README.rdoc
|
56
|
+
files:
|
57
|
+
- MIT_LICENSE
|
58
|
+
- README.rdoc
|
59
|
+
- Rakefile
|
60
|
+
- VERSION
|
61
|
+
- init.rb
|
62
|
+
- json_record.gemspec
|
63
|
+
- lib/json_record.rb
|
64
|
+
- lib/json_record/attribute_methods.rb
|
65
|
+
- lib/json_record/embedded_document.rb
|
66
|
+
- lib/json_record/embedded_document_array.rb
|
67
|
+
- lib/json_record/field_definition.rb
|
68
|
+
- lib/json_record/json_field.rb
|
69
|
+
- lib/json_record/schema.rb
|
70
|
+
- lib/json_record/serialized.rb
|
71
|
+
- spec/embedded_document_array_spec.rb
|
72
|
+
- spec/embedded_document_spec.rb
|
73
|
+
- spec/field_definition_spec.rb
|
74
|
+
- spec/serialized_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
- spec/test_models.rb
|
77
|
+
has_rdoc: true
|
78
|
+
homepage: http://github.com/bdurand/json_record
|
79
|
+
licenses: []
|
80
|
+
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options:
|
83
|
+
- --charset=UTF-8
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
version:
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: "0"
|
97
|
+
version:
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.3.5
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: ActiveRecord support for mapping complex documents within a single RDBMS record via JSON serialization.
|
105
|
+
test_files:
|
106
|
+
- spec/embedded_document_array_spec.rb
|
107
|
+
- spec/embedded_document_spec.rb
|
108
|
+
- spec/field_definition_spec.rb
|
109
|
+
- spec/serialized_spec.rb
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
- spec/test_models.rb
|