activerecord-typedstore 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -1
- data/README.md +6 -1
- data/Rakefile +18 -0
- data/lib/active_record/typed_store/extension.rb +31 -16
- data/lib/active_record/typed_store/version.rb +1 -1
- data/spec/active_record/typed_store_spec.rb +142 -31
- data/spec/support/models.rb +93 -27
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e093bbab4aa7f56fe8b248cbc6b3ffee4c896523
|
4
|
+
data.tar.gz: 101fbbb8b13b3687010ce3543e371be6b4561ff1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81ccdf476b884892c67460b9945784d593e50380a7e452452d0a3b54a60f82c3e39cf8a70f64bd154f01337ecac60675866f525aaf6d39a1536ed551c971d10b
|
7
|
+
data.tar.gz: da7fc4fc81c1cd22156b78dad835ee14ec788b9cdc69f7d2ccc839dc0e9f77fb5a024cf13dc159db43e297d6251f6e579759a061f2287fd85443bf23fc9b6a6b
|
data/.travis.yml
CHANGED
@@ -8,4 +8,7 @@ gemfile:
|
|
8
8
|
|
9
9
|
before_script:
|
10
10
|
- mysql -e 'create database typed_store_test;'
|
11
|
-
|
11
|
+
|
12
|
+
env:
|
13
|
+
- TIMEZONE_AWARE=1 POSTGRES=1 MYSQL=1 POSTGRES_URL=$(curl http://api.postgression.com)
|
14
|
+
- TIMEZONE_AWARE=0 POSTGRES=1 MYSQL=1 POSTGRES_URL=$(curl http://api.postgression.com)
|
data/README.md
CHANGED
@@ -36,7 +36,7 @@ class Shop < ActiveRecord::Base
|
|
36
36
|
s.string :email
|
37
37
|
s.datetime :publish_at
|
38
38
|
s.integer :age, null: false
|
39
|
-
|
39
|
+
|
40
40
|
# You can define array attributes like in rails 4 and postgres
|
41
41
|
s.string :tags, array: true, default: [], null: false
|
42
42
|
|
@@ -92,3 +92,8 @@ If not, please fill an issue.
|
|
92
92
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
93
93
|
4. Push to the branch (`git push origin my-new-feature`)
|
94
94
|
5. Create new Pull Request
|
95
|
+
|
96
|
+
## TODO
|
97
|
+
|
98
|
+
- HStore support with ActiveRecord 4.1.0.beta (master)
|
99
|
+
- Handle casting and default at the store layer, so accessors are not mandatory anymore. See #4
|
data/Rakefile
CHANGED
@@ -4,3 +4,21 @@ require 'rspec/core/rake_task'
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
6
|
task :default => :spec
|
7
|
+
|
8
|
+
namespace :spec do
|
9
|
+
task :all do
|
10
|
+
%w(3.2 4.0 edge).each do |ar_version|
|
11
|
+
[1, 0].each do |timezone_aware|
|
12
|
+
command = %W{
|
13
|
+
BUNDLE_GEMFILE=gemfiles/Gemfile.ar-#{ar_version}
|
14
|
+
TIMEZONE_AWARE=#{timezone_aware}
|
15
|
+
MYSQL=1
|
16
|
+
POSTGRES=1
|
17
|
+
rspec
|
18
|
+
}.join(' ')
|
19
|
+
puts command
|
20
|
+
puts `#{command}`
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -10,8 +10,10 @@ module ActiveRecord::TypedStore
|
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
12
|
included do
|
13
|
-
class_attribute :
|
14
|
-
|
13
|
+
class_attribute :typed_stores, instance_accessor: false
|
14
|
+
class_attribute :typed_store_attributes, instance_accessor: false
|
15
|
+
self.typed_stores = {}
|
16
|
+
self.typed_store_attributes = {}
|
15
17
|
end
|
16
18
|
|
17
19
|
module ClassMethods
|
@@ -19,10 +21,15 @@ module ActiveRecord::TypedStore
|
|
19
21
|
def typed_store(store_attribute, options={}, &block)
|
20
22
|
dsl = DSL.new(&block)
|
21
23
|
|
22
|
-
|
24
|
+
if hstore?(store_attribute)
|
25
|
+
store_accessor(store_attribute, dsl.column_names)
|
26
|
+
else
|
27
|
+
store(store_attribute, options.merge(accessors: dsl.column_names))
|
28
|
+
end
|
23
29
|
|
24
|
-
|
25
|
-
|
30
|
+
typed_stores[store_attribute] ||= {}
|
31
|
+
typed_stores[store_attribute].merge!(dsl.columns.index_by(&:name))
|
32
|
+
typed_store_attributes.merge!(dsl.columns.index_by { |c| c.name.to_s })
|
26
33
|
|
27
34
|
dsl.column_names.each { |c| define_virtual_attribute_method(c.to_s) }
|
28
35
|
dsl.column_names.each { |c| define_store_attribute_queries(store_attribute, c) }
|
@@ -34,6 +41,15 @@ module ActiveRecord::TypedStore
|
|
34
41
|
|
35
42
|
private
|
36
43
|
|
44
|
+
def hstore?(store_attribute)
|
45
|
+
columns_hash[store_attribute.to_s].try(:type) == :hstore
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_time_zone_conversion_attribute?(name, column)
|
49
|
+
column ||= typed_store_attributes[name]
|
50
|
+
super(name, column)
|
51
|
+
end
|
52
|
+
|
37
53
|
def define_store_attribute_queries(store_attribute, column_name)
|
38
54
|
define_method("#{column_name}?") do
|
39
55
|
query_store_attribute(store_attribute, column_name)
|
@@ -50,6 +66,11 @@ module ActiveRecord::TypedStore
|
|
50
66
|
protected
|
51
67
|
|
52
68
|
def write_store_attribute(store_attribute, key, value)
|
69
|
+
column = store_column_definition(store_attribute, key)
|
70
|
+
if column.try(:type) == :datetime && self.class.time_zone_aware_attributes && value.respond_to?(:in_time_zone)
|
71
|
+
value = value.in_time_zone
|
72
|
+
end
|
73
|
+
|
53
74
|
previous_value = read_store_attribute(store_attribute, key)
|
54
75
|
casted_value = cast_store_attribute(store_attribute, key, value)
|
55
76
|
attribute_will_change!(key.to_s) if casted_value != previous_value
|
@@ -64,7 +85,7 @@ module ActiveRecord::TypedStore
|
|
64
85
|
end
|
65
86
|
|
66
87
|
def store_column_definition(store_attribute, key)
|
67
|
-
store_definition = self.class.
|
88
|
+
store_definition = self.class.typed_stores[store_attribute]
|
68
89
|
store_definition && store_definition[key]
|
69
90
|
end
|
70
91
|
|
@@ -77,7 +98,7 @@ module ActiveRecord::TypedStore
|
|
77
98
|
end
|
78
99
|
|
79
100
|
def reload_stores!
|
80
|
-
self.class.
|
101
|
+
self.class.typed_stores.keys.each do |store_attribute|
|
81
102
|
instance_variable_set("@_#{store_attribute}_initialized", false)
|
82
103
|
end
|
83
104
|
end
|
@@ -86,7 +107,7 @@ module ActiveRecord::TypedStore
|
|
86
107
|
store = defined?(super) ? super : send(store_attribute)
|
87
108
|
store.tap do |store|
|
88
109
|
if_store_uninitialized(store_attribute) do
|
89
|
-
if columns = self.class.
|
110
|
+
if columns = self.class.typed_stores[store_attribute]
|
90
111
|
initialize_store(store, columns.values)
|
91
112
|
end
|
92
113
|
end
|
@@ -113,14 +134,8 @@ module ActiveRecord::TypedStore
|
|
113
134
|
when false, nil then false
|
114
135
|
else
|
115
136
|
column = store_column_definition(store_attribute, key)
|
116
|
-
|
117
|
-
|
118
|
-
!value.to_i.zero?
|
119
|
-
else
|
120
|
-
return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
|
121
|
-
!value.blank?
|
122
|
-
end
|
123
|
-
elsif column.number?
|
137
|
+
|
138
|
+
if column.number?
|
124
139
|
!value.zero?
|
125
140
|
else
|
126
141
|
!value.blank?
|
@@ -1,9 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
ar_version = Gem::Version.new(ActiveRecord::VERSION::STRING)
|
4
|
-
ar_4_0 = Gem::Version.new('4.0')
|
5
|
-
ar_4_1 = Gem::Version.new('4.1.0.beta')
|
6
|
-
|
7
3
|
shared_examples 'any model' do
|
8
4
|
|
9
5
|
let(:model) { described_class.new }
|
@@ -26,19 +22,6 @@ shared_examples 'any model' do
|
|
26
22
|
|
27
23
|
end
|
28
24
|
|
29
|
-
describe 'attribute presence' do
|
30
|
-
|
31
|
-
it 'return true if present' do
|
32
|
-
expect(model.age?).to be_true
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'return false if blank' do
|
36
|
-
model.age = 0
|
37
|
-
expect(model.age?).to be_false
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
25
|
describe 'dirty tracking' do
|
43
26
|
|
44
27
|
it 'track changed attributes' do
|
@@ -113,6 +96,19 @@ shared_examples 'any model' do
|
|
113
96
|
expect(model.reload.name).to be == '42'
|
114
97
|
end
|
115
98
|
|
99
|
+
it 'any string is considered present' do
|
100
|
+
model.name = 'Peter Gibbons'
|
101
|
+
expect(model.name?).to be_true
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'empty string is not considered present' do
|
105
|
+
expect(model.name?).to be_false
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'nil is not considered present' do
|
109
|
+
expect(model.cell_phone?).to be_false
|
110
|
+
end
|
111
|
+
|
116
112
|
end
|
117
113
|
|
118
114
|
describe 'boolean attribute' do
|
@@ -162,6 +158,19 @@ shared_examples 'any model' do
|
|
162
158
|
expect(model.reload.enabled).to be_true
|
163
159
|
end
|
164
160
|
|
161
|
+
it 'true is considered present' do
|
162
|
+
expect(model.enabled?).to be_true
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'false is not considered present' do
|
166
|
+
expect(model.public?).to be_false
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'nil is not considered present' do
|
170
|
+
model.update_attributes(enabled: nil)
|
171
|
+
expect(model.enabled?).to be_false
|
172
|
+
end
|
173
|
+
|
165
174
|
end
|
166
175
|
|
167
176
|
describe 'integer attributes' do
|
@@ -185,6 +194,25 @@ shared_examples 'any model' do
|
|
185
194
|
expect(model.reload.max_length).to be_nil
|
186
195
|
end
|
187
196
|
|
197
|
+
it 'positive values are considered present' do
|
198
|
+
expect(model.age?).to be_true
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'negative values are considered present' do
|
202
|
+
model.age = -42
|
203
|
+
expect(model.age?).to be_true
|
204
|
+
end
|
205
|
+
|
206
|
+
it '0 is not considered present' do
|
207
|
+
model.age = 0
|
208
|
+
expect(model.age?).to be_false
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'nil is not considered present' do
|
212
|
+
model.max_length = nil
|
213
|
+
expect(model.max_length?).to be_false
|
214
|
+
end
|
215
|
+
|
188
216
|
end
|
189
217
|
|
190
218
|
describe 'float attributes' do
|
@@ -208,6 +236,24 @@ shared_examples 'any model' do
|
|
208
236
|
expect(model.reload.price).to be_nil
|
209
237
|
end
|
210
238
|
|
239
|
+
it 'positive values are considered present' do
|
240
|
+
model.rate = 4.2
|
241
|
+
expect(model.rate?).to be_true
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'negative values are considered present' do
|
245
|
+
model.rate = -4.2
|
246
|
+
expect(model.rate?).to be_true
|
247
|
+
end
|
248
|
+
|
249
|
+
it '0 is not considered present' do
|
250
|
+
expect(model.rate?).to be_false
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'nil is not considered present' do
|
254
|
+
expect(model.price?).to be_false
|
255
|
+
end
|
256
|
+
|
211
257
|
end
|
212
258
|
|
213
259
|
describe 'decimal attributes' do
|
@@ -240,6 +286,25 @@ shared_examples 'any model' do
|
|
240
286
|
expect(model.reload.shipping_cost).to be_nil
|
241
287
|
end
|
242
288
|
|
289
|
+
it 'positive values are considered present' do
|
290
|
+
model.shipping_cost = BigDecimal.new('4.2')
|
291
|
+
expect(model.shipping_cost?).to be_true
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'negative values are considered present' do
|
295
|
+
model.shipping_cost = BigDecimal.new('-4.2')
|
296
|
+
expect(model.shipping_cost?).to be_true
|
297
|
+
end
|
298
|
+
|
299
|
+
it '0 is not considered present' do
|
300
|
+
model.shipping_cost = BigDecimal.new('0')
|
301
|
+
expect(model.shipping_cost?).to be_false
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'nil is not considered present' do
|
305
|
+
expect(model.shipping_cost?).to be_false
|
306
|
+
end
|
307
|
+
|
243
308
|
end
|
244
309
|
|
245
310
|
describe 'date attributes' do
|
@@ -270,17 +335,26 @@ shared_examples 'any model' do
|
|
270
335
|
expect(model.reload.remind_on).to be_nil
|
271
336
|
end
|
272
337
|
|
338
|
+
it 'any non-nil value is considered present' do
|
339
|
+
model.remind_on = Date.new
|
340
|
+
expect(model.remind_on?).to be_true
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'nil is not considered present' do
|
344
|
+
expect(model.remind_on?).to be_false
|
345
|
+
end
|
346
|
+
|
273
347
|
end
|
274
348
|
|
275
349
|
describe 'datetime attributes' do
|
276
350
|
|
277
351
|
let(:datetime) { DateTime.new(1984, 6, 8, 13, 57, 12) }
|
278
352
|
let(:datetime_string) { '1984-06-08 13:57:12' }
|
279
|
-
let(:time) { Time.parse(datetime_string) }
|
353
|
+
let(:time) { datetime_string.respond_to?(:in_time_zone) ? datetime_string.in_time_zone : Time.parse(datetime_string) }
|
280
354
|
|
281
355
|
context "with ActiveRecord #{ActiveRecord::VERSION::STRING}" do
|
282
356
|
|
283
|
-
if
|
357
|
+
if AR_VERSION < AR_4_0
|
284
358
|
|
285
359
|
it 'has the defined default as initial value' do
|
286
360
|
model.save
|
@@ -316,10 +390,22 @@ shared_examples 'any model' do
|
|
316
390
|
expect(model.reload.published_at).to be == datetime
|
317
391
|
end
|
318
392
|
|
319
|
-
|
320
|
-
|
321
|
-
|
393
|
+
if ActiveRecord::Base.time_zone_aware_attributes
|
394
|
+
|
395
|
+
it 'properly cast assigned value to time' do
|
396
|
+
model.remind_at = datetime_string
|
397
|
+
expect(model.remind_at).to be == time
|
398
|
+
end
|
399
|
+
|
400
|
+
else
|
401
|
+
|
402
|
+
it 'properly cast assigned value to datetime' do
|
403
|
+
model.remind_at = datetime_string
|
404
|
+
expect(model.remind_at).to be == datetime
|
405
|
+
end
|
406
|
+
|
322
407
|
end
|
408
|
+
|
323
409
|
end
|
324
410
|
|
325
411
|
end
|
@@ -334,11 +420,20 @@ shared_examples 'any model' do
|
|
334
420
|
expect(model.reload.remind_at).to be_nil
|
335
421
|
end
|
336
422
|
|
423
|
+
it 'any non-nil value is considered present' do
|
424
|
+
model.remind_at = DateTime.new
|
425
|
+
expect(model.remind_at?).to be_true
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'nil is not considered present' do
|
429
|
+
expect(model.remind_at?).to be_false
|
430
|
+
end
|
431
|
+
|
337
432
|
end
|
338
433
|
|
339
434
|
end
|
340
435
|
|
341
|
-
shared_examples 'a store' do
|
436
|
+
shared_examples 'a store' do |retain_type=true|
|
342
437
|
|
343
438
|
let(:model) { described_class.new }
|
344
439
|
|
@@ -396,7 +491,7 @@ shared_examples 'a store' do
|
|
396
491
|
expect(model.reload.author).to be == 'George'
|
397
492
|
|
398
493
|
model.update_attributes(author: 42)
|
399
|
-
expect(model.reload.author).to be == 42
|
494
|
+
expect(model.reload.author).to be == (retain_type ? 42 : '42')
|
400
495
|
end
|
401
496
|
|
402
497
|
it 'still handle default' do
|
@@ -420,7 +515,7 @@ shared_examples 'a db backed model' do
|
|
420
515
|
|
421
516
|
end
|
422
517
|
|
423
|
-
shared_examples 'a model supporting arrays' do |
|
518
|
+
shared_examples 'a model supporting arrays' do |pg_native=false|
|
424
519
|
|
425
520
|
let(:model) { described_class.new }
|
426
521
|
|
@@ -430,7 +525,7 @@ shared_examples 'a model supporting arrays' do |regular=false|
|
|
430
525
|
end
|
431
526
|
|
432
527
|
it 'cast values inside the array (integer)' do
|
433
|
-
pending('ActiveRecord bug: https://github.com/rails/rails/pull/11245') if
|
528
|
+
pending('ActiveRecord bug: https://github.com/rails/rails/pull/11245') if pg_native
|
434
529
|
model.update_attributes(grades: ['1', 2, 3.4])
|
435
530
|
expect(model.reload.grades).to be == [1, 2, 3]
|
436
531
|
end
|
@@ -450,14 +545,14 @@ shared_examples 'a model supporting arrays' do |regular=false|
|
|
450
545
|
expect(model.reload.grades).to be == []
|
451
546
|
end
|
452
547
|
|
453
|
-
if !
|
548
|
+
if !pg_native || AR_VERSION == AR_4_1
|
454
549
|
it 'accept multidimensianl arrays' do
|
455
550
|
model.update_attributes(grades: [[1, 2], [3, 4]])
|
456
551
|
expect(model.reload.grades).to be == [[1, 2], [3, 4]]
|
457
552
|
end
|
458
553
|
end
|
459
554
|
|
460
|
-
if
|
555
|
+
if pg_native
|
461
556
|
|
462
557
|
it 'raise on non rectangular multidimensianl arrays' do
|
463
558
|
expect{
|
@@ -487,6 +582,7 @@ shared_examples 'a model supporting arrays' do |regular=false|
|
|
487
582
|
|
488
583
|
end
|
489
584
|
|
585
|
+
|
490
586
|
describe Sqlite3RegularARModel do
|
491
587
|
it_should_behave_like 'any model'
|
492
588
|
it_should_behave_like 'a db backed model'
|
@@ -495,13 +591,28 @@ end
|
|
495
591
|
describe MysqlRegularARModel do
|
496
592
|
it_should_behave_like 'any model'
|
497
593
|
it_should_behave_like 'a db backed model'
|
498
|
-
end
|
594
|
+
end if defined?(MysqlRegularARModel)
|
499
595
|
|
500
596
|
describe PostgresqlRegularARModel do
|
501
597
|
it_should_behave_like 'any model'
|
502
598
|
it_should_behave_like 'a db backed model'
|
503
|
-
it_should_behave_like 'a model supporting arrays', true if
|
504
|
-
end
|
599
|
+
it_should_behave_like 'a model supporting arrays', true if AR_VERSION >= AR_4_0
|
600
|
+
end if defined?(PostgresqlRegularARModel)
|
601
|
+
|
602
|
+
describe PostgresHstoreTypedStoreModel do
|
603
|
+
if AR_VERSION >= AR_4_0
|
604
|
+
pending('TODO: Rails edge HStore compatibiliy')
|
605
|
+
else
|
606
|
+
it_should_behave_like 'any model'
|
607
|
+
it_should_behave_like 'a store', false
|
608
|
+
end
|
609
|
+
end if defined?(PostgresHstoreTypedStoreModel)
|
610
|
+
|
611
|
+
describe PostgresJsonTypedStoreModel do
|
612
|
+
it_should_behave_like 'any model'
|
613
|
+
it_should_behave_like 'a store'
|
614
|
+
it_should_behave_like 'a model supporting arrays'
|
615
|
+
end if defined?(PostgresJsonTypedStoreModel)
|
505
616
|
|
506
617
|
describe YamlTypedStoreModel do
|
507
618
|
it_should_behave_like 'any model'
|
data/spec/support/models.rb
CHANGED
@@ -2,6 +2,11 @@ require 'active_record'
|
|
2
2
|
require 'json'
|
3
3
|
require 'yaml'
|
4
4
|
|
5
|
+
AR_VERSION = Gem::Version.new(ActiveRecord::VERSION::STRING)
|
6
|
+
AR_4_0 = Gem::Version.new('4.0')
|
7
|
+
AR_4_1 = Gem::Version.new('4.1.0.beta')
|
8
|
+
|
9
|
+
ActiveRecord::Base.time_zone_aware_attributes = ENV['TIMEZONE_AWARE'] != '0'
|
5
10
|
ActiveRecord::Base.configurations = {
|
6
11
|
'test_sqlite3' => {adapter: 'sqlite3', database: "/tmp/typed_store.db"},
|
7
12
|
'test_postgresql' => {adapter: 'postgresql', database: 'typed_store_test', username: 'postgres'},
|
@@ -53,11 +58,23 @@ class CreateAllTables < ActiveRecord::Migration
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def self.up
|
56
|
-
|
57
|
-
|
61
|
+
if ENV['MYSQL']
|
62
|
+
ActiveRecord::Base.establish_connection('test_mysql')
|
63
|
+
recreate_table(:mysql_regular_ar_models) { |t| define_columns(t); t.text :untyped_settings }
|
64
|
+
end
|
65
|
+
|
66
|
+
if ENV['POSTGRES']
|
67
|
+
ActiveRecord::Base.establish_connection(ENV['POSTGRES_URL'] || 'test_postgresql')
|
68
|
+
recreate_table(:postgresql_regular_ar_models) { |t| define_columns(t); t.text :untyped_settings }
|
58
69
|
|
59
|
-
|
60
|
-
|
70
|
+
if AR_VERSION >= AR_4_0
|
71
|
+
execute "create extension if not exists hstore"
|
72
|
+
recreate_table(:postgres_hstore_typed_store_models) { |t| t.hstore :settings; t.text :untyped_settings }
|
73
|
+
|
74
|
+
#execute "create extension if not exists json"
|
75
|
+
recreate_table(:postgres_json_typed_store_models) { |t| t.json :settings; t.text :untyped_settings }
|
76
|
+
end
|
77
|
+
end
|
61
78
|
|
62
79
|
ActiveRecord::Base.establish_connection('test_sqlite3')
|
63
80
|
recreate_table(:sqlite3_regular_ar_models) { |t| define_columns(t); t.text :untyped_settings }
|
@@ -69,14 +86,68 @@ end
|
|
69
86
|
ActiveRecord::Migration.verbose = false
|
70
87
|
CreateAllTables.up
|
71
88
|
|
72
|
-
class
|
73
|
-
|
74
|
-
|
89
|
+
class ColumnCoder
|
90
|
+
|
91
|
+
def initialize(coder)
|
92
|
+
@coder = coder
|
93
|
+
end
|
94
|
+
|
95
|
+
def load(data)
|
96
|
+
return {} unless data
|
97
|
+
@coder.load(data)
|
98
|
+
end
|
99
|
+
|
100
|
+
def dump(data)
|
101
|
+
@coder.dump(data || {})
|
102
|
+
end
|
103
|
+
|
75
104
|
end
|
76
105
|
|
77
|
-
|
78
|
-
|
79
|
-
|
106
|
+
module AsJson
|
107
|
+
extend self
|
108
|
+
|
109
|
+
def load(value)
|
110
|
+
value
|
111
|
+
end
|
112
|
+
|
113
|
+
def dump(value)
|
114
|
+
value.as_json
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
if ENV['MYSQL']
|
120
|
+
class MysqlRegularARModel < ActiveRecord::Base
|
121
|
+
establish_connection 'test_mysql'
|
122
|
+
store :untyped_settings, accessors: [:title]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
if ENV['POSTGRES']
|
127
|
+
class PostgresqlRegularARModel < ActiveRecord::Base
|
128
|
+
establish_connection ENV['POSTGRES_URL'] || 'test_postgresql'
|
129
|
+
store :untyped_settings, accessors: [:title]
|
130
|
+
end
|
131
|
+
|
132
|
+
if AR_VERSION >= AR_4_0
|
133
|
+
|
134
|
+
class PostgresHstoreTypedStoreModel < ActiveRecord::Base
|
135
|
+
establish_connection ENV['POSTGRES_URL'] || 'test_postgresql'
|
136
|
+
store :untyped_settings, accessors: [:title]
|
137
|
+
typed_store :settings do |s|
|
138
|
+
define_store_columns(s)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class PostgresJsonTypedStoreModel < ActiveRecord::Base
|
143
|
+
establish_connection ENV['POSTGRES_URL'] || 'test_postgresql'
|
144
|
+
store :untyped_settings, accessors: [:title]
|
145
|
+
typed_store :settings, coder: ColumnCoder.new(AsJson) do |s|
|
146
|
+
define_store_columns(s)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
80
151
|
end
|
81
152
|
|
82
153
|
class Sqlite3RegularARModel < ActiveRecord::Base
|
@@ -92,23 +163,6 @@ class YamlTypedStoreModel < ActiveRecord::Base
|
|
92
163
|
end
|
93
164
|
end
|
94
165
|
|
95
|
-
class ColumnCoder
|
96
|
-
|
97
|
-
def initialize(coder)
|
98
|
-
@coder = coder
|
99
|
-
end
|
100
|
-
|
101
|
-
def load(data)
|
102
|
-
return {} unless data
|
103
|
-
@coder.load(data)
|
104
|
-
end
|
105
|
-
|
106
|
-
def dump(data)
|
107
|
-
@coder.dump(data || {})
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
166
|
class JsonTypedStoreModel < ActiveRecord::Base
|
113
167
|
establish_connection 'test_sqlite3'
|
114
168
|
store :untyped_settings, accessors: [:title]
|
@@ -124,3 +178,15 @@ class MarshalTypedStoreModel < ActiveRecord::Base
|
|
124
178
|
define_store_columns(s)
|
125
179
|
end
|
126
180
|
end
|
181
|
+
|
182
|
+
|
183
|
+
Models = [
|
184
|
+
Sqlite3RegularARModel,
|
185
|
+
YamlTypedStoreModel,
|
186
|
+
JsonTypedStoreModel,
|
187
|
+
MarshalTypedStoreModel
|
188
|
+
]
|
189
|
+
Models << MysqlRegularARModel if defined?(MysqlRegularARModel)
|
190
|
+
Models << PostgresqlRegularARModel if defined?(PostgresqlRegularARModel)
|
191
|
+
Models << PostgresHstoreTypedStoreModel if defined?(PostgresHstoreTypedStoreModel)
|
192
|
+
Models << PostgresJsonTypedStoreModel if defined?(PostgresJsonTypedStoreModel)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-typedstore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|