ar_jdbc_pg_array 0.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +48 -0
- data/Rakefile +7 -0
- data/ar_jdbc_pg_array.gemspec +24 -0
- data/lib/ar_jdbc_pg_array.rb +12 -0
- data/lib/ar_jdbc_pg_array/allways_save.rb +38 -0
- data/lib/ar_jdbc_pg_array/parser.rb +174 -0
- data/lib/ar_jdbc_pg_array/querying.rb +72 -0
- data/lib/ar_jdbc_pg_array/querying_arel.rb +172 -0
- data/lib/ar_jdbc_pg_array/references_by.rb +154 -0
- data/lib/ar_jdbc_pg_array/schema.rb +248 -0
- data/lib/ar_jdbc_pg_array/schema_arel.rb +47 -0
- data/lib/ar_jdbc_pg_array/schema_cacheable.rb +6 -0
- data/lib/ar_jdbc_pg_array/schema_fix_will_change.rb +13 -0
- data/spec/fixtures/bulk.rb +5 -0
- data/spec/fixtures/bulks.yml +36 -0
- data/spec/fixtures/item.rb +4 -0
- data/spec/fixtures/items.yml +22 -0
- data/spec/fixtures/schema.rb +30 -0
- data/spec/fixtures/tag.rb +2 -0
- data/spec/fixtures/tags.yml +15 -0
- data/spec/fixtures/unrelated.rb +21 -0
- data/spec/fixtures/unrelateds.yml +3 -0
- data/spec/pg_array_spec.rb +380 -0
- data/spec/spec_helper.rb +55 -0
- metadata +186 -0
@@ -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,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,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,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,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
|