arel 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/arel/algebra.rb +1 -0
- data/lib/arel/algebra/attributes.rb +1 -1
- data/lib/arel/algebra/attributes/attribute.rb +95 -7
- data/lib/arel/algebra/attributes/integer.rb +1 -1
- data/lib/arel/algebra/core_extensions/object.rb +0 -13
- data/lib/arel/algebra/header.rb +67 -0
- data/lib/arel/algebra/predicates.rb +153 -7
- data/lib/arel/algebra/relations/operations/having.rb +11 -7
- data/lib/arel/algebra/relations/operations/join.rb +1 -2
- data/lib/arel/algebra/relations/operations/project.rb +1 -1
- data/lib/arel/algebra/relations/relation.rb +13 -22
- data/lib/arel/algebra/relations/utilities/compound.rb +5 -1
- data/lib/arel/algebra/relations/utilities/externalization.rb +1 -1
- data/lib/arel/engines/memory/predicates.rb +58 -2
- data/lib/arel/engines/memory/relations/array.rb +6 -3
- data/lib/arel/engines/memory/relations/operations.rb +1 -1
- data/lib/arel/engines/sql/attributes.rb +1 -1
- data/lib/arel/engines/sql/core_extensions/array.rb +4 -0
- data/lib/arel/engines/sql/core_extensions/nil_class.rb +4 -0
- data/lib/arel/engines/sql/core_extensions/object.rb +4 -0
- data/lib/arel/engines/sql/core_extensions/range.rb +4 -0
- data/lib/arel/engines/sql/predicates.rb +48 -2
- data/lib/arel/engines/sql/primitives.rb +8 -0
- data/lib/arel/engines/sql/relations/compiler.rb +2 -2
- data/lib/arel/engines/sql/relations/operations/join.rb +1 -1
- data/lib/arel/engines/sql/relations/relation.rb +4 -0
- data/lib/arel/engines/sql/relations/table.rb +8 -4
- data/lib/arel/version.rb +1 -1
- data/spec/algebra/unit/relations/join_spec.rb +1 -2
- data/spec/algebra/unit/relations/table_spec.rb +1 -1
- data/spec/attributes/boolean_spec.rb +1 -1
- data/spec/attributes/float_spec.rb +1 -1
- data/spec/attributes/header_spec.rb +42 -0
- data/spec/attributes/integer_spec.rb +1 -1
- data/spec/attributes/string_spec.rb +1 -1
- data/spec/attributes/time_spec.rb +4 -2
- data/spec/engines/memory/integration/joins/cross_engine_spec.rb +3 -4
- data/spec/engines/sql/unit/predicates/in_spec.rb +23 -5
- data/spec/engines/sql/unit/predicates/noteq_spec.rb +75 -0
- data/spec/engines/sql/unit/primitives/attribute_spec.rb +0 -19
- data/spec/engines/sql/unit/relations/having_spec.rb +33 -0
- data/spec/relations/join_spec.rb +5 -3
- data/spec/relations/relation_spec.rb +2 -2
- data/spec/shared/relation_spec.rb +126 -13
- data/spec/support/check.rb +1 -1
- data/spec/support/connections/mysql_connection.rb +1 -1
- data/spec/support/connections/oracle_connection.rb +1 -1
- data/spec/support/connections/postgresql_connection.rb +1 -1
- data/spec/support/guards.rb +1 -1
- data/spec/support/matchers.rb +1 -1
- data/spec/support/matchers/be_like.rb +3 -3
- data/spec/support/matchers/have_rows.rb +1 -1
- data/spec/support/model.rb +6 -2
- metadata +7 -4
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe "Header" do
|
5
|
+
before :all do
|
6
|
+
@relation = Model.build do |r|
|
7
|
+
r.attribute :id, Attributes::Integer
|
8
|
+
r.attribute :name, Attributes::String
|
9
|
+
r.attribute :age, Attributes::Integer
|
10
|
+
end
|
11
|
+
|
12
|
+
@other = Model.build do |r|
|
13
|
+
r.attribute :foo, Attributes::String
|
14
|
+
end
|
15
|
+
|
16
|
+
@subset = Model.build do |r|
|
17
|
+
r.attribute :id, Attributes::Integer
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "attribute lookup" do
|
22
|
+
it "finds attributes by name" do
|
23
|
+
@relation.attributes[:name].should == Attributes::String.new(@relation, :name)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns nil if no attribute is found" do
|
27
|
+
@relation.attributes[:does_not_exist].should be_nil
|
28
|
+
@relation[:does_not_exist].should be_nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#union" do
|
33
|
+
it "keeps all attributes from disjoint headers" do
|
34
|
+
(@relation.attributes.union @other.attributes).to_ary.should have(4).items
|
35
|
+
end
|
36
|
+
|
37
|
+
it "keeps all attributes from both relations even if they seem like subsets" do
|
38
|
+
(@relation.attributes.union @subset.attributes).to_ary.should have(4).items
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -13,10 +13,9 @@ module Arel
|
|
13
13
|
@photos.insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6)
|
14
14
|
@photos.insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42)
|
15
15
|
# Oracle adapter returns database integers as Ruby integers and not strings
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
16
|
+
# So does the FFI sqlite library
|
17
|
+
db_int_return = @photos.project(@photos[:camera_id]).first.tuple.first
|
18
|
+
@adapter_returns_integer = db_int_return.is_a?(String) ? false : true
|
20
19
|
end
|
21
20
|
|
22
21
|
describe 'when the in memory relation is on the left' do
|
@@ -100,6 +100,28 @@ module Arel
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
+
describe 'when relating to a range with an excluded end' do
|
104
|
+
before do
|
105
|
+
@range = 1...3
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'manufactures sql with a >= and <' do
|
109
|
+
sql = In.new(@attribute, @range).to_sql
|
110
|
+
|
111
|
+
adapter_is :mysql do
|
112
|
+
sql.should be_like(%Q{(`users`.`id` >= 1 AND `users`.`id` < 3)})
|
113
|
+
end
|
114
|
+
|
115
|
+
adapter_is :oracle do
|
116
|
+
sql.should be_like(%Q{("USERS"."ID" >= 1 AND "USERS"."ID" < 3)})
|
117
|
+
end
|
118
|
+
|
119
|
+
adapter_is_not :mysql, :oracle do
|
120
|
+
sql.should be_like(%Q{("users"."id" >= 1 AND "users"."id" < 3)})
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
103
125
|
describe 'when relating to a time range' do
|
104
126
|
before do
|
105
127
|
@relation = Arel::Table.new(:developers)
|
@@ -115,11 +137,7 @@ module Arel
|
|
115
137
|
end
|
116
138
|
|
117
139
|
adapter_is :sqlite3 do
|
118
|
-
|
119
|
-
sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00.000000' AND '2010-02-01 00:00:00.000000'})
|
120
|
-
else
|
121
|
-
sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'})
|
122
|
-
end
|
140
|
+
sql.should match(/"developers"."created_at" BETWEEN '2010-01-01 00:00:00(?:\.\d+)' AND '2010-02-01 00:00:00(?:\.\d+)'/)
|
123
141
|
end
|
124
142
|
|
125
143
|
adapter_is :postgresql do
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Predicates
|
5
|
+
describe Equality do
|
6
|
+
before do
|
7
|
+
@relation1 = Arel::Table.new(:users)
|
8
|
+
@relation2 = Arel::Table.new(:photos)
|
9
|
+
@attribute1 = @relation1[:id]
|
10
|
+
@attribute2 = @relation2[:user_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#to_sql' do
|
14
|
+
describe 'when relating to a non-nil value' do
|
15
|
+
it "manufactures a not predicate" do
|
16
|
+
sql = Inequality.new(@attribute1, @attribute2).to_sql
|
17
|
+
|
18
|
+
adapter_is :mysql do
|
19
|
+
sql.should be_like(%Q{`users`.`id` != `photos`.`user_id`})
|
20
|
+
end
|
21
|
+
|
22
|
+
adapter_is :oracle do
|
23
|
+
sql.should be_like(%Q{"USERS"."ID" != "PHOTOS"."USER_ID"})
|
24
|
+
end
|
25
|
+
|
26
|
+
adapter_is_not :mysql, :oracle do
|
27
|
+
sql.should be_like(%Q{"users"."id" != "photos"."user_id"})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'when relation to a nil value' do
|
33
|
+
before do
|
34
|
+
@nil = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "manufactures an is null predicate" do
|
38
|
+
sql = Inequality.new(@attribute1, @nil).to_sql
|
39
|
+
|
40
|
+
adapter_is :mysql do
|
41
|
+
sql.should be_like(%Q{`users`.`id` IS NOT NULL})
|
42
|
+
end
|
43
|
+
|
44
|
+
adapter_is :oracle do
|
45
|
+
sql.should be_like(%Q{"USERS"."ID" IS NOT NULL})
|
46
|
+
end
|
47
|
+
|
48
|
+
adapter_is_not :mysql, :oracle do
|
49
|
+
sql.should be_like(%Q{"users"."id" IS NOT NULL})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "when relating to a nil Value" do
|
55
|
+
it "manufactures an IS NULL predicate" do
|
56
|
+
value = nil.bind(@relation1)
|
57
|
+
sql = Inequality.new(@attribute1, value).to_sql
|
58
|
+
|
59
|
+
adapter_is :mysql do
|
60
|
+
sql.should be_like(%Q{`users`.`id` IS NOT NULL})
|
61
|
+
end
|
62
|
+
|
63
|
+
adapter_is :oracle do
|
64
|
+
sql.should be_like(%Q{"USERS"."ID" IS NOT NULL})
|
65
|
+
end
|
66
|
+
|
67
|
+
adapter_is_not :mysql, :oracle do
|
68
|
+
sql.should be_like(%Q{"users"."id" IS NOT NULL})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -31,25 +31,6 @@ module Arel
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
35
|
-
describe 'for an inexistent attribute' do
|
36
|
-
it "manufactures sql" do
|
37
|
-
sql = @relation[:does_not_exist].to_sql
|
38
|
-
|
39
|
-
adapter_is :mysql do
|
40
|
-
sql.should be_like(%Q{`users`.`does_not_exist`})
|
41
|
-
end
|
42
|
-
|
43
|
-
adapter_is :oracle do
|
44
|
-
sql.should be_like(%Q{"USERS"."DOEST_NOT_EXIST"})
|
45
|
-
end
|
46
|
-
|
47
|
-
adapter_is_not :mysql, :oracle do
|
48
|
-
sql.should be_like(%Q{"users"."does_not_exist"})
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
34
|
end
|
54
35
|
end
|
55
36
|
end
|
@@ -39,6 +39,39 @@ module Arel
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
+
|
43
|
+
describe 'when given two predicates' do
|
44
|
+
it "manufactures sql with where clause conditions joined by AND" do
|
45
|
+
sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000", "MAX(salary) < 10000").to_sql
|
46
|
+
|
47
|
+
adapter_is :mysql do
|
48
|
+
sql.should be_like(%Q{
|
49
|
+
SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department`, `developers`.`created_at`
|
50
|
+
FROM `developers`
|
51
|
+
GROUP BY `developers`.`department`
|
52
|
+
HAVING MIN(salary) > 1000 AND MAX(salary) < 10000
|
53
|
+
})
|
54
|
+
end
|
55
|
+
|
56
|
+
adapter_is :oracle do
|
57
|
+
sql.should be_like(%Q{
|
58
|
+
SELECT "DEVELOPERS"."ID", "DEVELOPERS"."NAME", "DEVELOPERS"."SALARY", "DEVELOPERS"."DEPARTMENT", "DEVELOPERS"."CREATED_AT"
|
59
|
+
FROM "DEVELOPERS"
|
60
|
+
GROUP BY "DEVELOPERS"."DEPARTMENT"
|
61
|
+
HAVING MIN(salary) > 1000 AND MAX(salary) < 10000
|
62
|
+
})
|
63
|
+
end
|
64
|
+
|
65
|
+
adapter_is_not :mysql, :oracle do
|
66
|
+
sql.should be_like(%Q{
|
67
|
+
SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department", "developers"."created_at"
|
68
|
+
FROM "developers"
|
69
|
+
GROUP BY "developers"."department"
|
70
|
+
HAVING MIN(salary) > 1000 AND MAX(salary) < 10000
|
71
|
+
})
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
42
75
|
end
|
43
76
|
end
|
44
77
|
end
|
data/spec/relations/join_spec.rb
CHANGED
@@ -13,6 +13,7 @@ describe "Arel" do
|
|
13
13
|
|
14
14
|
r.attribute :id, Arel::Attributes::Integer
|
15
15
|
r.attribute :owner_id, Arel::Attributes::Integer
|
16
|
+
r.attribute :name, Arel::Attributes::String
|
16
17
|
r.attribute :age, Arel::Attributes::Integer
|
17
18
|
end
|
18
19
|
end
|
@@ -28,13 +29,14 @@ describe "Arel" do
|
|
28
29
|
8.times do |i|
|
29
30
|
thing_id = owner_id * 8 + i
|
30
31
|
age = 2 * thing_id
|
32
|
+
name = "Name #{thing_id % 6}"
|
31
33
|
|
32
|
-
@thing.insert([thing_id, owner_id, age])
|
33
|
-
@expected << Arel::Row.new(@relation, [thing_id, owner_id, age, owner_id])
|
34
|
+
@thing.insert([thing_id, owner_id, name, age])
|
35
|
+
@expected << Arel::Row.new(@relation, [thing_id, owner_id, name, age, owner_id])
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
it_should_behave_like 'A Relation'
|
39
41
|
end
|
40
|
-
end
|
42
|
+
end
|
@@ -14,7 +14,7 @@ describe "Arel" do
|
|
14
14
|
|
15
15
|
describe "Relation" do
|
16
16
|
before :all do
|
17
|
-
@expected = (1..20).map { |i| @relation.insert([i,
|
17
|
+
@expected = (1..20).map { |i| @relation.insert([i, "Name #{i % 6}", 2 * i]) }
|
18
18
|
end
|
19
19
|
|
20
20
|
it_should_behave_like 'A Relation'
|
@@ -28,4 +28,4 @@ describe "Arel" do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
@@ -35,9 +35,19 @@ share_examples_for 'A Relation' do
|
|
35
35
|
@relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected)
|
36
36
|
end
|
37
37
|
|
38
|
-
it "finds rows with
|
38
|
+
it "finds rows with an equal to complement predicate" do
|
39
39
|
expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] }
|
40
|
-
@relation.where(@relation[:age].
|
40
|
+
@relation.where(@relation[:age].eq(@pivot[@relation[:age]]).complement).should have_rows(expected)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "finds rows with a not eq predicate" do
|
44
|
+
expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] }
|
45
|
+
@relation.where(@relation[:age].not_eq(@pivot[@relation[:age]])).should have_rows(expected)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "finds rows with an not eq complement predicate" do
|
49
|
+
expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] }
|
50
|
+
@relation.where(@relation[:age].not_eq(@pivot[@relation[:age]]).complement).should have_rows(expected)
|
41
51
|
end
|
42
52
|
|
43
53
|
it "finds rows with a less than predicate" do
|
@@ -45,52 +55,155 @@ share_examples_for 'A Relation' do
|
|
45
55
|
@relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected)
|
46
56
|
end
|
47
57
|
|
58
|
+
it "finds rows with a less than complement predicate" do
|
59
|
+
expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] }
|
60
|
+
@relation.where(@relation[:age].lt(@pivot[@relation[:age]]).complement).should have_rows(expected)
|
61
|
+
end
|
62
|
+
|
48
63
|
it "finds rows with a less than or equal to predicate" do
|
49
64
|
expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] }
|
50
65
|
@relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected)
|
51
66
|
end
|
52
67
|
|
68
|
+
it "finds rows with a less than or equal to complement predicate" do
|
69
|
+
expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] }
|
70
|
+
@relation.where(@relation[:age].lteq(@pivot[@relation[:age]]).complement).should have_rows(expected)
|
71
|
+
end
|
72
|
+
|
53
73
|
it "finds rows with a greater than predicate" do
|
54
74
|
expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] }
|
55
75
|
@relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected)
|
56
76
|
end
|
57
77
|
|
78
|
+
it "finds rows with a greater than complement predicate" do
|
79
|
+
expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] }
|
80
|
+
@relation.where(@relation[:age].gt(@pivot[@relation[:age]]).complement).should have_rows(expected)
|
81
|
+
end
|
82
|
+
|
58
83
|
it "finds rows with a greater than or equal to predicate" do
|
59
84
|
expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] }
|
60
85
|
@relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected)
|
61
86
|
end
|
62
87
|
|
63
|
-
it "finds rows with a
|
88
|
+
it "finds rows with a greater than or equal to complement predicate" do
|
89
|
+
expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] }
|
90
|
+
@relation.where(@relation[:age].gteq(@pivot[@relation[:age]]).complement).should have_rows(expected)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "finds rows with a matches predicate" do
|
94
|
+
expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ }
|
95
|
+
@relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "finds rows with a matches complement predicate" do
|
99
|
+
expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ }
|
100
|
+
@relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "finds rows with a not matches predicate" do
|
104
|
+
expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ }
|
105
|
+
@relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "finds rows with a not matches complement predicate" do
|
109
|
+
expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ }
|
110
|
+
@relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected)
|
111
|
+
end
|
64
112
|
|
65
113
|
it "finds rows with an in predicate" do
|
66
|
-
|
67
|
-
|
68
|
-
|
114
|
+
expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20}
|
115
|
+
@relation.where(@relation[:age].in(3..20)).should have_rows(expected)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "finds rows with an in complement predicate" do
|
119
|
+
expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)}
|
120
|
+
@relation.where(@relation[:age].in(3..20).complement).should have_rows(expected)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "finds rows with a not in predicate" do
|
124
|
+
expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)}
|
125
|
+
@relation.where(@relation[:age].not_in(3..20)).should have_rows(expected)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "finds rows with a not in complement predicate" do
|
129
|
+
expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20}
|
130
|
+
@relation.where(@relation[:age].not_in(3..20).complement).should have_rows(expected)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "finds rows with a polyadic predicate of class Any" do
|
134
|
+
expected = @expected.select {|r| [2,4,8,16].include?(r[@relation[:age]])}
|
135
|
+
@relation.where(@relation[:age].in_any([2,4], [8, 16])).should have_rows(expected)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "finds rows with a polyadic predicate of class Any complement" do
|
139
|
+
expected = @expected.select {|r| ![2,4,8,16].include?(r[@relation[:age]])}
|
140
|
+
@relation.where(@relation[:age].in_any([2,4], [8, 16]).complement).should have_rows(expected)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "finds rows with a polyadic predicate of class All" do
|
144
|
+
expected = @expected.select {|r| r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/}
|
145
|
+
@relation.where(@relation[:name].matches_all(/Name/, /1/)).should have_rows(expected)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "finds rows with a polyadic predicate of class All complement" do
|
149
|
+
expected = @expected.select {|r| !(r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/)}
|
150
|
+
@relation.where(@relation[:name].matches_all(/Name/, /1/).complement).should have_rows(expected)
|
69
151
|
end
|
70
152
|
end
|
71
153
|
|
72
154
|
describe "#order" do
|
73
155
|
describe "by one attribute" do
|
74
156
|
before :all do
|
75
|
-
@expected.
|
76
|
-
@expected.sort!
|
157
|
+
@expected.sort! { |a, b| a[@relation[:age]] <=> b[@relation[:age]]}.map! {|e| e[@relation[:id]]}
|
77
158
|
end
|
78
159
|
|
79
160
|
it "can be specified as ascending order" do
|
80
161
|
actual = []
|
81
|
-
@relation.order(@relation[:age].asc).each { |r| actual << r[@relation[:
|
162
|
+
@relation.order(@relation[:age].asc).each { |r| actual << r[@relation[:id]] }
|
82
163
|
actual.should == @expected
|
83
164
|
end
|
84
165
|
|
85
166
|
it "can be specified as descending order" do
|
86
167
|
actual = []
|
87
|
-
@relation.order(@relation[:age].desc).each { |r| actual << r[@relation[:
|
168
|
+
@relation.order(@relation[:age].desc).each { |r| actual << r[@relation[:id]] }
|
88
169
|
actual.should == @expected.reverse
|
89
170
|
end
|
90
171
|
end
|
91
172
|
|
92
|
-
describe "by two attributes" do
|
93
|
-
|
173
|
+
describe "by two attributes in two separate calls to #order" do
|
174
|
+
before :all do
|
175
|
+
@expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]}
|
176
|
+
end
|
177
|
+
|
178
|
+
it "can be specified as ascending order" do
|
179
|
+
actual = []
|
180
|
+
@relation.order(@relation[:age].asc).order(@relation[:name].asc).each { |r| actual << r[@relation[:id]] }
|
181
|
+
actual.should == @expected
|
182
|
+
end
|
183
|
+
|
184
|
+
it "can be specified as descending order" do
|
185
|
+
actual = []
|
186
|
+
@relation.order(@relation[:age].desc).order(@relation[:name].desc).each { |r| actual << r[@relation[:id]] }
|
187
|
+
actual.should == @expected.reverse
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "by two attributes in one call to #order" do
|
192
|
+
before :all do
|
193
|
+
@expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]}
|
194
|
+
end
|
195
|
+
|
196
|
+
it "can be specified as ascending order in one call to #order" do
|
197
|
+
actual = []
|
198
|
+
@relation.order(@relation[:name].asc, @relation[:age].asc).each { |r| actual << r[@relation[:id]] }
|
199
|
+
actual.should == @expected
|
200
|
+
end
|
201
|
+
|
202
|
+
it "can be specified as descending order in one call to #order" do
|
203
|
+
actual = []
|
204
|
+
@relation.order(@relation[:name].desc, @relation[:age].desc).each { |r| actual << r[@relation[:id]] }
|
205
|
+
actual.should == @expected.reverse
|
206
|
+
end
|
94
207
|
end
|
95
208
|
end
|
96
209
|
|
@@ -139,4 +252,4 @@ share_examples_for 'A Relation' do
|
|
139
252
|
actual.should == expected[3..-1]
|
140
253
|
end
|
141
254
|
end
|
142
|
-
end
|
255
|
+
end
|