activerecord-typedstore 0.3.0 → 0.3.1
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 +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
|