arel 0.3.3 → 0.4.0
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.
- 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
|