ar_jdbc_pg_array 0.1.0-java

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.
@@ -0,0 +1,6 @@
1
+ atcbd = ActiveRecord::AttributeMethods::Read::ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
2
+
3
+ atcbd << /_array$/
4
+ def atcbd.include?(val)
5
+ any?{|type| type === val}
6
+ end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ module Dirty
3
+ private
4
+ def attribute_will_change!(attr)
5
+ val = changed_attributes[attr] = clone_attribute_value(:read_attribute, attr)
6
+ if Array === val && !(Array === @attributes[attr])
7
+ send(attr) unless @attributes_cache.has_key?(attr)
8
+ @attributes[attr] = @attributes_cache[attr]
9
+ end
10
+ val
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class Bulk < ActiveRecord::Base
2
+ end
3
+
4
+ class Bulk1 < Bulk
5
+ end
@@ -0,0 +1,36 @@
1
+ first:
2
+ id: 1
3
+ ints: [ 1 ]
4
+ strings: [ one ]
5
+ times: [2011-03-01, 2011-05-05]
6
+ floats: [1.0, 2.3]
7
+ decimals: [1.0, 2.3]
8
+ second:
9
+ id: 2
10
+ ints: [ 2 ]
11
+ strings: [ two ]
12
+ times: [2010-01-01, 2010-02-01]
13
+ floats: [2.0, 2.3]
14
+ decimals: [2.0, 2.3]
15
+ third:
16
+ id: 3
17
+ ints: [ 2, 3 ]
18
+ strings: [ two, three ]
19
+ times: [2010-03-01, 2010-04-01]
20
+ floats: [2.0, 2.5]
21
+ decimals: [2.0, 2.5]
22
+ fourth:
23
+ id: 4
24
+ ints: [ ]
25
+ strings: [ ]
26
+ times: [ ]
27
+ floats: [ ]
28
+ decimals: [ ]
29
+ fifth:
30
+ id: 5
31
+ type: "Bulk1"
32
+ ints: [ 10 ]
33
+ strings: [ "#{1+1}", "\\#{1+1}\"'\\z\x01", "\t\n" ]
34
+ times: [ ]
35
+ floats: [ ]
36
+ decimals: [ ]
@@ -0,0 +1,4 @@
1
+ class Item < ActiveRecord::Base
2
+ references_by_array :tags, :validate=>true
3
+ serialize :for_yaml
4
+ end
@@ -0,0 +1,22 @@
1
+ i1:
2
+ id: 1
3
+ tag_ids: [ 1 ]
4
+ i2:
5
+ id: 2
6
+ tag_ids: [ 3 ]
7
+ i3:
8
+ id: 3
9
+ tag_ids: [ 1, 3 ]
10
+ i4:
11
+ id: 4
12
+ tag_ids: [ 3, 1 ]
13
+ i5:
14
+ id: 5
15
+ tag_ids: [ 1, 2 ]
16
+ i6:
17
+ id: 6
18
+ tag_ids: [ 1, 2, 3 ]
19
+ i7:
20
+ id: 7
21
+ tag_ids: [ ]
22
+
@@ -0,0 +1,30 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table "tags", :force => true do |t|
3
+ t.string :name
4
+ t.timestamps
5
+ end
6
+
7
+ create_table "items", :force => true do |t|
8
+ t.string :value
9
+ t.integer_array :tag_ids, :default => [1, 2]
10
+ t.string_array :tag_names, :default => %w{as so}
11
+ t.text :for_yaml
12
+ end
13
+
14
+ create_table "bulks", :force => true do |t|
15
+ t.string :type, :default => "Bulk"
16
+ t.string :value, :default => "'"
17
+ t.integer_array :ints, :default => [1, 2]
18
+ t.string_array :strings, :default => %w{as so}
19
+ t.timestamp_array :times, :default => %w{2010-01-01 2010-02-01}
20
+ t.float_array :floats, :default => [1.0, 1.2]
21
+ t.decimal_array :decimals, :default => [1.0, 1.2]
22
+ t.text_array :texts, :default => [nil, 'Text', 'NULL', 'Text with nil', 'Text with , nil, !"\\', 'nil']
23
+ t.integer_array :empty_def, :default => []
24
+ end
25
+
26
+ create_table "unrelateds", :force => true do |t|
27
+ t.text :for_yaml
28
+ t.text :for_custom_serialize
29
+ end
30
+ end
@@ -0,0 +1,2 @@
1
+ class Tag < ActiveRecord::Base
2
+ end
@@ -0,0 +1,15 @@
1
+ one:
2
+ id: 1
3
+ name: one
4
+ created_at: <%= Date.today.to_s(:db) %>
5
+ updated_at: <%= Time.now.to_s(:db) %>
6
+ two:
7
+ id: 2
8
+ name: two
9
+ created_at: <%= Date.today.to_s(:db) %>
10
+ updated_at: <%= Time.now.to_s(:db) %>
11
+ three:
12
+ id: 3
13
+ name: three
14
+ created_at: <%= Date.today.to_s(:db) %>
15
+ updated_at: <%= Time.now.to_s(:db) %>
@@ -0,0 +1,21 @@
1
+ require 'base64'
2
+ class Unrelated < ActiveRecord::Base
3
+ class MySerializer
4
+ def initialize(val)
5
+ @val = val
6
+ end
7
+
8
+ def self.dump(obj)
9
+ Base64.encode64(Marshal.dump(obj))
10
+ end
11
+
12
+ def self.load(str)
13
+ if str
14
+ Marshal.load(Base64.decode64(str))
15
+ end
16
+ end
17
+ end
18
+
19
+ serialize :for_yaml
20
+ serialize :for_custom_serialize, MySerializer
21
+ end
@@ -0,0 +1,3 @@
1
+ item1:
2
+ id: 1
3
+ for_yaml: {"a": "b"}
@@ -0,0 +1,380 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "PgArray" do
4
+ context "Array" do
5
+ before :all do
6
+ @ability_class = Class.new do
7
+ include CanCan::Ability
8
+ end
9
+ @acheck = Struct.new(:a)
10
+ end
11
+
12
+ before :each do
13
+ @ability = @ability_class.new
14
+ end
15
+
16
+ it "should change type" do
17
+ [].pg.should be_an_instance_of(PGArrays::PgArray)
18
+ [].search_any.should be_an_instance_of(PGArrays::PgAny)
19
+ [].search_all.should be_an_instance_of(PGArrays::PgAll)
20
+ [].search_subarray.should be_an_instance_of(PGArrays::PgIncludes)
21
+ end
22
+
23
+ it "should provide search_any for cancan" do
24
+ ab.can :boom, @acheck, :a => [1, 2].search_any
25
+ ab.should be_able_to(:boom, the([1]))
26
+ ab.should be_able_to(:boom, the([1, 3]))
27
+ ab.should be_able_to(:boom, the([3, 1]))
28
+ ab.should be_able_to(:boom, the([1, 2]))
29
+ ab.should be_able_to(:boom, the([1, 2, 3]))
30
+ ab.should_not be_able_to(:boom, the([3]))
31
+ ab.should_not be_able_to(:boom, the([]))
32
+ end
33
+
34
+ it "should provide search_all for cancan" do
35
+ ab.can :boom, @acheck, :a => [1, 2].search_all
36
+ ab.should_not be_able_to(:boom, the([1]))
37
+ ab.should_not be_able_to(:boom, the([1, 3]))
38
+ ab.should_not be_able_to(:boom, the([3, 1]))
39
+ ab.should be_able_to(:boom, the([1, 2]))
40
+ ab.should be_able_to(:boom, the([1, 2, 3]))
41
+ ab.should_not be_able_to(:boom, the([3]))
42
+ ab.should_not be_able_to(:boom, the([]))
43
+ end
44
+
45
+ it "should provide search_subarray for cancan" do
46
+ ab.can :boom, @acheck, :a => [1, 2].search_subarray
47
+ ab.should be_able_to(:boom, the([1]))
48
+ ab.should_not be_able_to(:boom, the([1, 3]))
49
+ ab.should_not be_able_to(:boom, the([3, 1]))
50
+ ab.should be_able_to(:boom, the([1, 2]))
51
+ ab.should_not be_able_to(:boom, the([1, 2, 3]))
52
+ ab.should_not be_able_to(:boom, the([3]))
53
+ ab.should be_able_to(:boom, the([]))
54
+ end
55
+
56
+ def the(ar)
57
+ @acheck.new(ar)
58
+ end
59
+
60
+ def ab
61
+ @ability
62
+ end
63
+ end
64
+
65
+ context "AR" do
66
+ it "should adequatly insert fixtures" do
67
+ bulk = Bulk.find(1)
68
+ bulk.ints.should == [ 1 ]
69
+ bulk.strings.should == %w{one}
70
+ map_times(bulk.times).should ==
71
+ map_times(parse_times(%w{2011-03-01 2011-05-05}))
72
+ bulk.floats.should == [1.0, 2.3]
73
+ bulk.decimals.should == [1.0, 2.3]
74
+ end
75
+
76
+ it "should be created with defaults" do
77
+ bulk = Bulk.new
78
+ bulk.ints.should == [1, 2]
79
+ bulk.strings.should == %w{as so}
80
+ bulk.floats.should == [1.0, 1.2]
81
+ bulk.decimals.should == [1.0, 1.2]
82
+ bulk.texts.should == [nil, 'Text', 'NULL', 'Text with nil', 'Text with , nil, !"\\', 'nil']
83
+ map_times(bulk.times).should ==
84
+ map_times(parse_times(%w{2010-01-01 2010-02-01}))
85
+ bulk.empty_def.should == []
86
+ end
87
+
88
+ it "should be able to insert" do
89
+ bulki = Bulk.new
90
+ bulki.save
91
+ bulk = Bulk.find(bulki.id)
92
+ bulk.ints.should == [1, 2]
93
+ bulk.strings.should == %w{as so}
94
+ bulk.floats.should == [1.0, 1.2]
95
+ bulk.decimals.should == [1.0, 1.2]
96
+ bulk.texts.should == [nil, 'Text', 'NULL', 'Text with nil', 'Text with , nil, !"\\', 'nil']
97
+ map_times(bulk.times).should ==
98
+ map_times(parse_times(%w{2010-01-01 2010-02-01}))
99
+ bulk.empty_def.should == []
100
+ bulk.destroy
101
+ end
102
+
103
+ it "should not alter defaults" do
104
+ bulk = Bulk.new
105
+ bulk.strings.push :foo
106
+ bulk = Bulk.new
107
+ bulk.strings.should == %w{as so}
108
+ end
109
+
110
+ it "should save changes" do
111
+ bulk = Bulk.find(3)
112
+ for field in %w{ints strings floats decimals times}
113
+ bulk.send(field+'=', bulk.send(field).reverse)
114
+ end
115
+ bulk.save!
116
+ bulk = Bulk.find(:first, :conditions=>'3 = id')
117
+ bulk.ints.should == [3, 2]
118
+ bulk.strings.should == %w{three two}
119
+ bulk.floats.should == [2.5, 2]
120
+ bulk.decimals.should == [2.5, 2]
121
+ map_times(bulk.times).should == map_times(parse_times(%w{2010-04-01 2010-03-01}))
122
+ end
123
+
124
+ it "should save right text" do
125
+ bulk = Bulk.find(5)
126
+ bulk.texts = ['Text with , nil, !\x01\\\'"',"Text with , nil, !\x01\n\\\'\""]
127
+ bulk.save!
128
+ bulk.texts = []
129
+ bulk = Bulk.find(:first, :conditions=>'5 = id')
130
+ bulk.texts.should == ['Text with , nil, !\x01\\\'"',"Text with , nil, !\x01\n\\\'\""]
131
+ end
132
+
133
+ it "should save nested arrays" do
134
+ Bulk.transaction do
135
+ bulk = Bulk.find(3)
136
+ bulk.ints = [[1,2],[3,4]]
137
+ bulk.floats = [[1.0, 2.3e34],[3.43,6.21]]
138
+ bulk.times = [parse_times(%w{2010-04-01 2011-04-01}), parse_times(%w{2011-05-01 2010-05-01})]
139
+ bulk.save!
140
+ bulk = Bulk.find(:first, :conditions=>'3 = id')
141
+ bulk.ints.should == [[1,2],[3,4]]
142
+ bulk.floats.should == [[1.0, 2.3e34],[3.43,6.21]]
143
+ bulk.times.map{|ts| map_times(ts)}.should == [
144
+ map_times(parse_times(%w{2010-04-01 2011-04-01})),
145
+ map_times(parse_times(%w{2011-05-01 2010-05-01}))]
146
+ raise ActiveRecord::Rollback
147
+ end
148
+ end
149
+
150
+ it "should save right nested text" do
151
+ Bulk.transaction do
152
+ bulk = Bulk.find(5)
153
+ bulk.texts = [['Text with , nil, !\x01\\\'"',"Text with , nil, !\x01\n\\\'\""], ['asdf', 'fdsa']]
154
+ bulk.save!
155
+ bulk.texts = []
156
+ bulk = Bulk.find(:first, :conditions=>'5 = id')
157
+ bulk.texts.should == [['Text with , nil, !\x01\\\'"',"Text with , nil, !\x01\n\\\'\""], ['asdf', 'fdsa']]
158
+ raise ActiveRecord::Rollback
159
+ end
160
+ end
161
+
162
+ it "should be safe for eval" do
163
+ bulk = Bulk.find(5)
164
+ bulk.strings.should == ["\#{1+1}", "\\\#{1+1}\"'\\z\x01", "\t\n"]
165
+ #$stderr.puts ActiveRecord::ConnectionAdapters::PostgreSQLColumn::ESCAPE_ARRAY.inspect
166
+ end
167
+
168
+ it "should allow to use sql" do
169
+ bulks_where(['ints && ?', [1,2].pg]).should == bulks_where(:id=>[1,2,3])
170
+ end
171
+
172
+ it "should allow to use finders" do
173
+ bulks_where(:ints => [2].search_any).should == bulks_where(:id=>[2,3])
174
+ bulks_where(:ints => [2,3].search_any).should == bulks_where(:id=>[2,3])
175
+ bulks_where(:ints => [1,2].search_any).should == bulks_where(:id=>[1,2,3])
176
+
177
+ bulks_where(:ints => [2].search_all).should == bulks_where(:id=>[2,3])
178
+ bulks_where(:ints => [2,3].search_all).should == bulks_where(:id=>[3])
179
+ bulks_where(:ints => [1,2].search_all).should == []
180
+
181
+ bulks_where(:ints => [2].search_subarray).should == bulks_where(:id=>[2,4])
182
+ bulks_where(:ints => [2,3].search_subarray).should == bulks_where(:id=>[2,3,4])
183
+ bulks_where(:ints => [1,2].search_subarray).should == bulks_where(:id=>[1,2,4])
184
+ end
185
+
186
+ it "should be cached in @attributes_cache" do
187
+ bulk = Bulk.find(1)
188
+ ar = bulk.ints
189
+ bulk.ints.should.equal?(ar)
190
+ ard = ar.dup
191
+ arn = (bulk.ints << 1)
192
+ arn.should equal(ar)
193
+ bulk.ints.should equal(ar)
194
+ bulk.ints.should == (ard + [1])
195
+ end
196
+
197
+ it 'should allways save changed value' do
198
+ bulk = Bulk.find(1)
199
+ old = bulk.ints.dup
200
+ bulk.ints << 2
201
+ new = bulk.ints.dup
202
+ bulk.save
203
+ bulk.reload
204
+ bulk.ints.should == new
205
+ end
206
+
207
+ it 'should not break yaml serialization on model with array' do
208
+ item = Item.find(1)
209
+ item.for_yaml = {:a => :b}
210
+ item.save.should be_true
211
+ copy = Item.find(1)
212
+ copy.for_yaml.should == {:a => :b}
213
+ copy.for_yaml = ['a', 'b']
214
+ copy.save.should be_true
215
+ copy = Item.find(1)
216
+ copy.for_yaml.should == ['a', 'b']
217
+ end
218
+
219
+ it 'should not break yaml serialization on unrelated model' do
220
+ item = Unrelated.find(1)
221
+ item.for_yaml.should == {'a' => 'b'}
222
+ item.for_yaml = {:a => :b}
223
+ item.save.should be_true
224
+ copy = Unrelated.find(1)
225
+ copy.for_yaml.should == {:a => :b}
226
+ copy.for_yaml = ['a', 'b']
227
+ copy.save.should be_true
228
+ copy = Unrelated.find(1)
229
+ copy.for_yaml.should == ['a', 'b']
230
+ end
231
+
232
+ it 'should not break custom serialization on model with array' do
233
+ obj = Unrelated::MySerializer.new(%w{hello world})
234
+ model = Unrelated.create!(:for_custom_serialize => obj)
235
+ model.for_custom_serialize.to_yaml.should == obj.to_yaml
236
+ model2 = Unrelated.find(model.id)
237
+ model2.for_custom_serialize.to_yaml.should == obj.to_yaml
238
+ end
239
+
240
+ it 'should be workable with sti' do
241
+ obj = Bulk1.where(:ints => [10].pg).first
242
+ obj.should be_instance_of Bulk1
243
+ obj.floats = [1.1, 2.2]
244
+ obj.save
245
+ obj1 = Bulk.find(obj.id)
246
+ obj1.should be_instance_of Bulk1
247
+ obj1.floats.should == [1.1, 2.2]
248
+ obj2 = Bulk1.new
249
+ obj2.save
250
+ obj2.destroy
251
+ end
252
+
253
+ def map_times(times)
254
+ times.map{|t| t.strftime("%F %T")}
255
+ end
256
+
257
+ def parse_times(times)
258
+ times.map{|t| DateTime.parse(t)}
259
+ end
260
+
261
+ def bulks_where(cond)
262
+ Bulk.where(cond).order('id').all
263
+ end
264
+ end
265
+
266
+ context "CanCan" do
267
+ before :all do
268
+ @ability_class = Class.new do
269
+ include CanCan::Ability
270
+ end
271
+ @all_items = Item.all
272
+ end
273
+
274
+ before :each do
275
+ @ability = @ability_class.new
276
+ end
277
+
278
+ it "should provide search_any for cancan" do
279
+ should_match_ids_with_ability [2, 3, 4, 6], :tag_ids => [3].search_any
280
+ should_match_ids_with_ability [1, 3, 4, 5, 6], :tag_ids => [1, 2].search_any
281
+ end
282
+
283
+ it "should provide search_all for cancan" do
284
+ should_match_ids_with_ability [2, 3, 4, 6], :tag_ids => [3].search_all
285
+ should_match_ids_with_ability [5, 6], :tag_ids => [1, 2].search_all
286
+ end
287
+
288
+ it "should provide search_subarray for cancan" do
289
+ should_match_ids_with_ability [2, 7], :tag_ids => [3].search_subarray
290
+ should_match_ids_with_ability [1, 5, 7], :tag_ids => [1, 2].search_subarray
291
+ end
292
+
293
+ def should_match_ids_with_ability(ids, ability)
294
+ act = (ability[:tag_ids].class.name + ids.join('_')).to_sym
295
+ ab.can act, Item, ability
296
+ items = accessible_items(act)
297
+ items.should == items_where(:id=>ids)
298
+ should_be_able_all items, act
299
+ should_not_be_able_except items, act
300
+ end
301
+
302
+ def ab
303
+ @ability
304
+ end
305
+
306
+ def accessible_items(act)
307
+ Item.accessible_by(ab, act).order('id').all
308
+ end
309
+
310
+ def items_where(cond)
311
+ Item.where(cond).order('id').all
312
+ end
313
+
314
+ def should_be_able_all(items, act)
315
+ items.each{|item| ab.should be_able_to(act, item)}
316
+ end
317
+
318
+ def should_not_be_able_except(items, act)
319
+ (@all_items - items).each{|item| ab.should_not be_able_to(act, items)}
320
+ end
321
+ end
322
+
323
+ context "references_by" do
324
+ it "should fetch tags in saved order" do
325
+ Item.find(3).tags.should == [Tag.find(1), Tag.find(3)]
326
+ Item.find(4).tags.should == [Tag.find(3), Tag.find(1)]
327
+ end
328
+
329
+ it "should save tags references" do
330
+ item = Item.find(3)
331
+ item.tags= [Tag.find(1), '3', 2]
332
+ item.tags.should == [Tag.find(1), Tag.find(3), Tag.find(2)]
333
+ item.save!
334
+ item.reload
335
+ item.tags.should == [Tag.find(1), Tag.find(3), Tag.find(2)]
336
+ item.tags= [1,3]
337
+ item.save!
338
+ item.reload
339
+ item.tags.should == [Tag.find(1), Tag.find(3)]
340
+ end
341
+
342
+ it "should define named scopes for tags" do
343
+ Item.tags_include(3).order('id').all.should == items_where(:id=>[2,3,4,6])
344
+ Item.tags_include(1,3).order('id').all.should == items_where(:id=>[3,4,6])
345
+ Item.tags_have_all(3).order('id').all.should == items_where(:id=>[2,3,4,6])
346
+ Item.tags_have_all(1,3).order('id').all.should == items_where(:id=>[3,4,6])
347
+ Item.tags_have_any(3).order('id').all.should == items_where(:id=>[2,3,4,6])
348
+ Item.tags_have_any(1,3).order('id').all.should == items_where(:id=>[1,2,3,4,5,6])
349
+ Item.tags_included_into(3).order('id').all.should == items_where(:id=>[2,7])
350
+ Item.tags_included_into(1,3).order('id').all.should == items_where(:id=>[1,2,3,4,7])
351
+ end
352
+
353
+ def items_where(cond)
354
+ Item.where(cond).order('id').all
355
+ end
356
+ end
357
+
358
+ context "schema" do
359
+ it "should allow to add column" do
360
+ lambda do
361
+ ActiveRecord::Schema.define do
362
+ change_table :items do |t|
363
+ t.integer_array :ints, :default=>[], :null=>false
364
+ end
365
+ add_column :items, :floats, :float_array, :default=>[0], :null=>false
366
+ end
367
+ end.should_not raise_error
368
+ end
369
+
370
+ it "should not break other add_column" do
371
+ lambda do
372
+ ActiveRecord::Schema.define do
373
+ add_column :items, :float1, :float
374
+ add_column :items, :float2, :float, :null=>true
375
+ add_column :items, :float3, :float, :default=>0, :null=>false
376
+ end
377
+ end.should_not raise_error
378
+ end
379
+ end
380
+ end