square-arel 2.0.9.20110222133018
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/.autotest +26 -0
- data/History.txt +105 -0
- data/MIT-LICENSE.txt +20 -0
- data/Manifest.txt +124 -0
- data/README.markdown +94 -0
- data/Rakefile +20 -0
- data/lib/arel.rb +39 -0
- data/lib/arel/attributes.rb +20 -0
- data/lib/arel/attributes/attribute.rb +18 -0
- data/lib/arel/compatibility/wheres.rb +33 -0
- data/lib/arel/crud.rb +37 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/deprecated.rb +4 -0
- data/lib/arel/expression.rb +4 -0
- data/lib/arel/expressions.rb +23 -0
- data/lib/arel/insert_manager.rb +34 -0
- data/lib/arel/nodes.rb +53 -0
- data/lib/arel/nodes/and.rb +6 -0
- data/lib/arel/nodes/as.rb +6 -0
- data/lib/arel/nodes/assignment.rb +6 -0
- data/lib/arel/nodes/avg.rb +6 -0
- data/lib/arel/nodes/between.rb +6 -0
- data/lib/arel/nodes/binary.rb +12 -0
- data/lib/arel/nodes/count.rb +13 -0
- data/lib/arel/nodes/delete_statement.rb +19 -0
- data/lib/arel/nodes/does_not_match.rb +6 -0
- data/lib/arel/nodes/equality.rb +9 -0
- data/lib/arel/nodes/except.rb +7 -0
- data/lib/arel/nodes/exists.rb +7 -0
- data/lib/arel/nodes/function.rb +18 -0
- data/lib/arel/nodes/greater_than.rb +6 -0
- data/lib/arel/nodes/greater_than_or_equal.rb +6 -0
- data/lib/arel/nodes/group.rb +6 -0
- data/lib/arel/nodes/grouping.rb +6 -0
- data/lib/arel/nodes/having.rb +6 -0
- data/lib/arel/nodes/in.rb +6 -0
- data/lib/arel/nodes/inner_join.rb +6 -0
- data/lib/arel/nodes/insert_statement.rb +19 -0
- data/lib/arel/nodes/intersect.rb +7 -0
- data/lib/arel/nodes/join.rb +13 -0
- data/lib/arel/nodes/less_than.rb +6 -0
- data/lib/arel/nodes/less_than_or_equal.rb +6 -0
- data/lib/arel/nodes/limit.rb +7 -0
- data/lib/arel/nodes/lock.rb +6 -0
- data/lib/arel/nodes/matches.rb +6 -0
- data/lib/arel/nodes/max.rb +6 -0
- data/lib/arel/nodes/min.rb +6 -0
- data/lib/arel/nodes/node.rb +44 -0
- data/lib/arel/nodes/not.rb +6 -0
- data/lib/arel/nodes/not_equal.rb +6 -0
- data/lib/arel/nodes/not_in.rb +6 -0
- data/lib/arel/nodes/offset.rb +7 -0
- data/lib/arel/nodes/on.rb +6 -0
- data/lib/arel/nodes/or.rb +6 -0
- data/lib/arel/nodes/ordering.rb +20 -0
- data/lib/arel/nodes/outer_join.rb +6 -0
- data/lib/arel/nodes/select_core.rb +26 -0
- data/lib/arel/nodes/select_statement.rb +22 -0
- data/lib/arel/nodes/sql_literal.rb +8 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/sum.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +13 -0
- data/lib/arel/nodes/top.rb +6 -0
- data/lib/arel/nodes/unary.rb +11 -0
- data/lib/arel/nodes/union.rb +7 -0
- data/lib/arel/nodes/union_all.rb +7 -0
- data/lib/arel/nodes/unqualified_column.rb +16 -0
- data/lib/arel/nodes/update_statement.rb +21 -0
- data/lib/arel/nodes/values.rb +14 -0
- data/lib/arel/predications.rb +183 -0
- data/lib/arel/relation.rb +6 -0
- data/lib/arel/select_manager.rb +237 -0
- data/lib/arel/sql/engine.rb +10 -0
- data/lib/arel/sql_literal.rb +4 -0
- data/lib/arel/table.rb +134 -0
- data/lib/arel/tree_manager.rb +36 -0
- data/lib/arel/update_manager.rb +49 -0
- data/lib/arel/visitors.rb +38 -0
- data/lib/arel/visitors/depth_first.rb +154 -0
- data/lib/arel/visitors/dot.rb +230 -0
- data/lib/arel/visitors/join_sql.rb +40 -0
- data/lib/arel/visitors/mssql.rb +16 -0
- data/lib/arel/visitors/mysql.rb +34 -0
- data/lib/arel/visitors/oracle.rb +116 -0
- data/lib/arel/visitors/order_clauses.rb +11 -0
- data/lib/arel/visitors/postgresql.rb +58 -0
- data/lib/arel/visitors/sqlite.rb +11 -0
- data/lib/arel/visitors/to_sql.rb +331 -0
- data/lib/arel/visitors/visitor.rb +27 -0
- data/lib/arel/visitors/where_sql.rb +9 -0
- data/square-arel.gemspec +36 -0
- data/test/attributes/test_attribute.rb +664 -0
- data/test/helper.rb +13 -0
- data/test/nodes/test_as.rb +16 -0
- data/test/nodes/test_count.rb +18 -0
- data/test/nodes/test_delete_statement.rb +14 -0
- data/test/nodes/test_equality.rb +74 -0
- data/test/nodes/test_insert_statement.rb +18 -0
- data/test/nodes/test_node.rb +33 -0
- data/test/nodes/test_not.rb +20 -0
- data/test/nodes/test_or.rb +22 -0
- data/test/nodes/test_select_core.rb +22 -0
- data/test/nodes/test_select_statement.rb +13 -0
- data/test/nodes/test_sql_literal.rb +52 -0
- data/test/nodes/test_sum.rb +12 -0
- data/test/nodes/test_update_statement.rb +18 -0
- data/test/support/fake_record.rb +91 -0
- data/test/test_activerecord_compat.rb +18 -0
- data/test/test_attributes.rb +46 -0
- data/test/test_crud.rb +69 -0
- data/test/test_delete_manager.rb +42 -0
- data/test/test_insert_manager.rb +125 -0
- data/test/test_select_manager.rb +659 -0
- data/test/test_table.rb +193 -0
- data/test/test_update_manager.rb +86 -0
- data/test/visitors/test_depth_first.rb +212 -0
- data/test/visitors/test_dot.rb +29 -0
- data/test/visitors/test_join_sql.rb +35 -0
- data/test/visitors/test_mssql.rb +18 -0
- data/test/visitors/test_mysql.rb +45 -0
- data/test/visitors/test_oracle.rb +147 -0
- data/test/visitors/test_postgres.rb +36 -0
- data/test/visitors/test_sqlite.rb +18 -0
- data/test/visitors/test_to_sql.rb +255 -0
- metadata +261 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe 'activerecord compatibility' do
|
5
|
+
describe 'select manager' do
|
6
|
+
it 'provides wheres' do
|
7
|
+
table = Table.new :users
|
8
|
+
manager = Arel::SelectManager.new Table.engine
|
9
|
+
manager.where table[:id].eq 1
|
10
|
+
manager.where table[:name].eq 'Aaron'
|
11
|
+
|
12
|
+
manager.wheres.map { |x|
|
13
|
+
x.value
|
14
|
+
}.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe 'Attributes' do
|
5
|
+
describe 'for' do
|
6
|
+
it 'deals with unknown column types' do
|
7
|
+
column = Struct.new(:type).new :crazy
|
8
|
+
Attributes.for(column).must_equal Attributes::Undefined
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns the correct constant for strings' do
|
12
|
+
[:string, :text, :binary].each do |type|
|
13
|
+
column = Struct.new(:type).new type
|
14
|
+
Attributes.for(column).must_equal Attributes::String
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns the correct constant for ints' do
|
19
|
+
column = Struct.new(:type).new :integer
|
20
|
+
Attributes.for(column).must_equal Attributes::Integer
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the correct constant for floats' do
|
24
|
+
column = Struct.new(:type).new :float
|
25
|
+
Attributes.for(column).must_equal Attributes::Float
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns the correct constant for decimals' do
|
29
|
+
column = Struct.new(:type).new :decimal
|
30
|
+
Attributes.for(column).must_equal Attributes::Decimal
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns the correct constant for boolean' do
|
34
|
+
column = Struct.new(:type).new :boolean
|
35
|
+
Attributes.for(column).must_equal Attributes::Boolean
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns the correct constant for time' do
|
39
|
+
[:date, :datetime, :timestamp, :time].each do |type|
|
40
|
+
column = Struct.new(:type).new type
|
41
|
+
Attributes.for(column).must_equal Attributes::Time
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/test/test_crud.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
class FakeCrudder < SelectManager
|
5
|
+
class FakeEngine
|
6
|
+
attr_reader :calls, :connection_pool, :spec, :config
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@calls = []
|
10
|
+
@connection_pool = self
|
11
|
+
@spec = self
|
12
|
+
@config = { :adapter => 'sqlite3' }
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection; self end
|
16
|
+
|
17
|
+
def method_missing name, *args
|
18
|
+
@calls << [name, args]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
include Crud
|
23
|
+
|
24
|
+
attr_reader :engine
|
25
|
+
attr_accessor :ctx
|
26
|
+
|
27
|
+
def initialize engine = FakeEngine.new
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'crud' do
|
33
|
+
describe 'insert' do
|
34
|
+
it 'should call insert on the connection' do
|
35
|
+
table = Table.new :users
|
36
|
+
fc = FakeCrudder.new
|
37
|
+
fc.from table
|
38
|
+
fc.insert [[table[:id], 'foo']]
|
39
|
+
fc.engine.calls.find { |method, _|
|
40
|
+
method == :insert
|
41
|
+
}.wont_be_nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'update' do
|
46
|
+
it 'should call update on the connection' do
|
47
|
+
table = Table.new :users
|
48
|
+
fc = FakeCrudder.new
|
49
|
+
fc.from table
|
50
|
+
fc.update [[table[:id], 'foo']]
|
51
|
+
fc.engine.calls.find { |method, _|
|
52
|
+
method == :update
|
53
|
+
}.wont_be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'delete' do
|
58
|
+
it 'should call delete on the connection' do
|
59
|
+
table = Table.new :users
|
60
|
+
fc = FakeCrudder.new
|
61
|
+
fc.from table
|
62
|
+
fc.delete
|
63
|
+
fc.engine.calls.find { |method, _|
|
64
|
+
method == :delete
|
65
|
+
}.wont_be_nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe 'delete manager' do
|
5
|
+
describe 'new' do
|
6
|
+
it 'takes an engine' do
|
7
|
+
Arel::DeleteManager.new Table.engine
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'from' do
|
12
|
+
it 'uses from' do
|
13
|
+
table = Table.new(:users)
|
14
|
+
dm = Arel::DeleteManager.new Table.engine
|
15
|
+
dm.from table
|
16
|
+
dm.to_sql.must_be_like %{ DELETE FROM "users" }
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'chains' do
|
20
|
+
table = Table.new(:users)
|
21
|
+
dm = Arel::DeleteManager.new Table.engine
|
22
|
+
dm.from(table).must_equal dm
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'where' do
|
27
|
+
it 'uses where values' do
|
28
|
+
table = Table.new(:users)
|
29
|
+
dm = Arel::DeleteManager.new Table.engine
|
30
|
+
dm.from table
|
31
|
+
dm.where table[:id].eq(10)
|
32
|
+
dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10}
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'chains' do
|
36
|
+
table = Table.new(:users)
|
37
|
+
dm = Arel::DeleteManager.new Table.engine
|
38
|
+
dm.where(table[:id].eq(10)).must_equal dm
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe 'insert manager' do
|
5
|
+
describe 'new' do
|
6
|
+
it 'takes an engine' do
|
7
|
+
Arel::InsertManager.new Table.engine
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'insert' do
|
12
|
+
it "inserts false" do
|
13
|
+
table = Table.new(:users)
|
14
|
+
manager = Arel::InsertManager.new Table.engine
|
15
|
+
|
16
|
+
manager.insert [[table[:bool], false]]
|
17
|
+
manager.to_sql.must_be_like %{
|
18
|
+
INSERT INTO "users" ("bool") VALUES ('f')
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "inserts null" do
|
23
|
+
table = Table.new(:users)
|
24
|
+
manager = Arel::InsertManager.new Table.engine
|
25
|
+
manager.insert [[table[:id], nil]]
|
26
|
+
manager.to_sql.must_be_like %{
|
27
|
+
INSERT INTO "users" ("id") VALUES (NULL)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "inserts time" do
|
32
|
+
table = Table.new(:users)
|
33
|
+
manager = Arel::InsertManager.new Table.engine
|
34
|
+
|
35
|
+
time = Time.now
|
36
|
+
attribute = table[:created_at]
|
37
|
+
|
38
|
+
manager.insert [[attribute, time]]
|
39
|
+
manager.to_sql.must_be_like %{
|
40
|
+
INSERT INTO "users" ("created_at") VALUES (#{Table.engine.connection.quote time})
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'takes a list of lists' do
|
45
|
+
table = Table.new(:users)
|
46
|
+
manager = Arel::InsertManager.new Table.engine
|
47
|
+
manager.into table
|
48
|
+
manager.insert [[table[:id], 1], [table[:name], 'aaron']]
|
49
|
+
manager.to_sql.must_be_like %{
|
50
|
+
INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'defaults the table' do
|
55
|
+
table = Table.new(:users)
|
56
|
+
manager = Arel::InsertManager.new Table.engine
|
57
|
+
manager.insert [[table[:id], 1], [table[:name], 'aaron']]
|
58
|
+
manager.to_sql.must_be_like %{
|
59
|
+
INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'takes an empty list' do
|
64
|
+
manager = Arel::InsertManager.new Table.engine
|
65
|
+
manager.insert []
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'into' do
|
70
|
+
it 'takes an engine' do
|
71
|
+
manager = Arel::InsertManager.new Table.engine
|
72
|
+
manager.into(Table.new(:users)).must_equal manager
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'converts to sql' do
|
76
|
+
table = Table.new :users
|
77
|
+
manager = Arel::InsertManager.new Table.engine
|
78
|
+
manager.into table
|
79
|
+
manager.to_sql.must_be_like %{
|
80
|
+
INSERT INTO "users"
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'columns' do
|
86
|
+
it "converts to sql" do
|
87
|
+
table = Table.new :users
|
88
|
+
manager = Arel::InsertManager.new Table.engine
|
89
|
+
manager.into table
|
90
|
+
manager.columns << table[:id]
|
91
|
+
manager.to_sql.must_be_like %{
|
92
|
+
INSERT INTO "users" ("id")
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "values" do
|
98
|
+
it "converts to sql" do
|
99
|
+
table = Table.new :users
|
100
|
+
manager = Arel::InsertManager.new Table.engine
|
101
|
+
manager.into table
|
102
|
+
|
103
|
+
manager.values = Nodes::Values.new [1]
|
104
|
+
manager.to_sql.must_be_like %{
|
105
|
+
INSERT INTO "users" VALUES (1)
|
106
|
+
}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "combo" do
|
111
|
+
it "puts shit together" do
|
112
|
+
table = Table.new :users
|
113
|
+
manager = Arel::InsertManager.new Table.engine
|
114
|
+
manager.into table
|
115
|
+
|
116
|
+
manager.values = Nodes::Values.new [1, 'aaron']
|
117
|
+
manager.columns << table[:id]
|
118
|
+
manager.columns << table[:name]
|
119
|
+
manager.to_sql.must_be_like %{
|
120
|
+
INSERT INTO "users" ("id", "name") VALUES (1, 'aaron')
|
121
|
+
}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,659 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
class EngineProxy
|
5
|
+
attr_reader :executed
|
6
|
+
attr_reader :connection_pool
|
7
|
+
attr_reader :spec
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
def initialize engine
|
11
|
+
@engine = engine
|
12
|
+
@executed = []
|
13
|
+
@connection_pool = self
|
14
|
+
@spec = self
|
15
|
+
@config = { :adapter => 'sqlite3' }
|
16
|
+
end
|
17
|
+
|
18
|
+
def with_connection
|
19
|
+
yield self
|
20
|
+
end
|
21
|
+
|
22
|
+
def connection
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def quote_table_name thing; @engine.connection.quote_table_name thing end
|
27
|
+
def quote_column_name thing; @engine.connection.quote_column_name thing end
|
28
|
+
def quote thing, column; @engine.connection.quote thing, column end
|
29
|
+
|
30
|
+
def execute sql, name = nil, *args
|
31
|
+
@executed << sql
|
32
|
+
end
|
33
|
+
alias :update :execute
|
34
|
+
alias :delete :execute
|
35
|
+
alias :insert :execute
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'select manager' do
|
39
|
+
describe 'backwards compatibility' do
|
40
|
+
describe 'project' do
|
41
|
+
it 'accepts symbols as sql literals' do
|
42
|
+
table = Table.new :users
|
43
|
+
manager = Arel::SelectManager.new Table.engine
|
44
|
+
manager.project :id
|
45
|
+
manager.from table
|
46
|
+
manager.to_sql.must_be_like %{
|
47
|
+
SELECT id FROM "users"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'order' do
|
53
|
+
it 'accepts symbols' do
|
54
|
+
table = Table.new :users
|
55
|
+
manager = Arel::SelectManager.new Table.engine
|
56
|
+
manager.project SqlLiteral.new '*'
|
57
|
+
manager.from table
|
58
|
+
manager.order :foo
|
59
|
+
manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'group' do
|
64
|
+
it 'takes a symbol' do
|
65
|
+
table = Table.new :users
|
66
|
+
manager = Arel::SelectManager.new Table.engine
|
67
|
+
manager.from table
|
68
|
+
manager.group :foo
|
69
|
+
manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'from' do
|
74
|
+
it 'ignores strings when table of same name exists' do
|
75
|
+
table = Table.new :users
|
76
|
+
manager = Arel::SelectManager.new Table.engine
|
77
|
+
|
78
|
+
manager.from table
|
79
|
+
manager.from 'users'
|
80
|
+
manager.project table['id']
|
81
|
+
manager.to_sql.must_be_like 'SELECT "users"."id" FROM users'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#having' do
|
86
|
+
it 'converts strings to SQLLiterals' do
|
87
|
+
table = Table.new :users
|
88
|
+
mgr = table.from table
|
89
|
+
mgr.having 'foo'
|
90
|
+
mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'on' do
|
95
|
+
it 'converts to sqlliterals' do
|
96
|
+
table = Table.new :users
|
97
|
+
right = table.alias
|
98
|
+
mgr = table.from table
|
99
|
+
mgr.join(right).on("omg")
|
100
|
+
mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg }
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'converts to sqlliterals' do
|
104
|
+
table = Table.new :users
|
105
|
+
right = table.alias
|
106
|
+
mgr = table.from table
|
107
|
+
mgr.join(right).on("omg", "123")
|
108
|
+
mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg AND 123 }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'clone' do
|
114
|
+
it 'creates new cores' do
|
115
|
+
table = Table.new :users, :engine => Table.engine, :as => 'foo'
|
116
|
+
mgr = table.from table
|
117
|
+
m2 = mgr.clone
|
118
|
+
m2.project "foo"
|
119
|
+
mgr.to_sql.wont_equal m2.to_sql
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'initialize' do
|
124
|
+
it 'uses alias in sql' do
|
125
|
+
table = Table.new :users, :engine => Table.engine, :as => 'foo'
|
126
|
+
mgr = table.from table
|
127
|
+
mgr.skip 10
|
128
|
+
mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe 'skip' do
|
133
|
+
it 'should add an offset' do
|
134
|
+
table = Table.new :users
|
135
|
+
mgr = table.from table
|
136
|
+
mgr.skip 10
|
137
|
+
mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should chain' do
|
141
|
+
table = Table.new :users
|
142
|
+
mgr = table.from table
|
143
|
+
mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'exists' do
|
148
|
+
it 'should create an exists clause' do
|
149
|
+
table = Table.new(:users)
|
150
|
+
manager = Arel::SelectManager.new Table.engine, table
|
151
|
+
manager.project SqlLiteral.new '*'
|
152
|
+
m2 = Arel::SelectManager.new(manager.engine)
|
153
|
+
m2.project manager.exists
|
154
|
+
m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) }
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'can be aliased' do
|
158
|
+
table = Table.new(:users)
|
159
|
+
manager = Arel::SelectManager.new Table.engine, table
|
160
|
+
manager.project SqlLiteral.new '*'
|
161
|
+
m2 = Arel::SelectManager.new(manager.engine)
|
162
|
+
m2.project manager.exists.as('foo')
|
163
|
+
m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe 'ast' do
|
168
|
+
it 'should return the ast' do
|
169
|
+
table = Table.new :users
|
170
|
+
mgr = table.from table
|
171
|
+
ast = mgr.ast
|
172
|
+
mgr.visitor.accept(ast).must_equal mgr.to_sql
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe 'taken' do
|
177
|
+
it 'should return limit' do
|
178
|
+
manager = Arel::SelectManager.new Table.engine
|
179
|
+
manager.take 10
|
180
|
+
manager.taken.must_equal 10
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe 'insert' do
|
185
|
+
it 'uses the select FROM' do
|
186
|
+
engine = EngineProxy.new Table.engine
|
187
|
+
table = Table.new :users
|
188
|
+
manager = Arel::SelectManager.new engine
|
189
|
+
manager.from table
|
190
|
+
manager.insert 'VALUES(NULL)'
|
191
|
+
|
192
|
+
engine.executed.last.must_be_like %{
|
193
|
+
INSERT INTO "users" VALUES(NULL)
|
194
|
+
}
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe 'lock' do
|
199
|
+
# This should fail on other databases
|
200
|
+
it 'adds a lock node' do
|
201
|
+
table = Table.new :users
|
202
|
+
mgr = table.from table
|
203
|
+
mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe 'orders' do
|
208
|
+
it 'returns order clauses' do
|
209
|
+
table = Table.new :users
|
210
|
+
manager = Arel::SelectManager.new Table.engine
|
211
|
+
order = table[:id]
|
212
|
+
manager.order table[:id]
|
213
|
+
manager.orders.must_equal [order]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe 'order' do
|
218
|
+
it 'generates order clauses' do
|
219
|
+
table = Table.new :users
|
220
|
+
manager = Arel::SelectManager.new Table.engine
|
221
|
+
manager.project SqlLiteral.new '*'
|
222
|
+
manager.from table
|
223
|
+
manager.order table[:id]
|
224
|
+
manager.to_sql.must_be_like %{
|
225
|
+
SELECT * FROM "users" ORDER BY "users"."id"
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
229
|
+
# FIXME: I would like to deprecate this
|
230
|
+
it 'takes *args' do
|
231
|
+
table = Table.new :users
|
232
|
+
manager = Arel::SelectManager.new Table.engine
|
233
|
+
manager.project SqlLiteral.new '*'
|
234
|
+
manager.from table
|
235
|
+
manager.order table[:id], table[:name]
|
236
|
+
manager.to_sql.must_be_like %{
|
237
|
+
SELECT * FROM "users" ORDER BY "users"."id", "users"."name"
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'chains' do
|
242
|
+
table = Table.new :users
|
243
|
+
manager = Arel::SelectManager.new Table.engine
|
244
|
+
manager.order(table[:id]).must_equal manager
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe 'on' do
|
249
|
+
it 'takes two params' do
|
250
|
+
left = Table.new :users
|
251
|
+
right = left.alias
|
252
|
+
predicate = left[:id].eq(right[:id])
|
253
|
+
manager = Arel::SelectManager.new Table.engine
|
254
|
+
|
255
|
+
manager.from left
|
256
|
+
manager.join(right).on(predicate, predicate)
|
257
|
+
manager.to_sql.must_be_like %{
|
258
|
+
SELECT FROM "users"
|
259
|
+
INNER JOIN "users" "users_2"
|
260
|
+
ON "users"."id" = "users_2"."id" AND
|
261
|
+
"users"."id" = "users_2"."id"
|
262
|
+
}
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'takes three params' do
|
266
|
+
left = Table.new :users
|
267
|
+
right = left.alias
|
268
|
+
predicate = left[:id].eq(right[:id])
|
269
|
+
manager = Arel::SelectManager.new Table.engine
|
270
|
+
|
271
|
+
manager.from left
|
272
|
+
manager.join(right).on(
|
273
|
+
predicate,
|
274
|
+
predicate,
|
275
|
+
left[:name].eq(right[:name])
|
276
|
+
)
|
277
|
+
manager.to_sql.must_be_like %{
|
278
|
+
SELECT FROM "users"
|
279
|
+
INNER JOIN "users" "users_2"
|
280
|
+
ON "users"."id" = "users_2"."id" AND
|
281
|
+
"users"."id" = "users_2"."id" AND
|
282
|
+
"users"."name" = "users_2"."name"
|
283
|
+
}
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe 'join' do
|
288
|
+
it 'responds to join' do
|
289
|
+
left = Table.new :users
|
290
|
+
right = left.alias
|
291
|
+
predicate = left[:id].eq(right[:id])
|
292
|
+
manager = Arel::SelectManager.new Table.engine
|
293
|
+
|
294
|
+
manager.from left
|
295
|
+
manager.join(right).on(predicate)
|
296
|
+
manager.to_sql.must_be_like %{
|
297
|
+
SELECT FROM "users"
|
298
|
+
INNER JOIN "users" "users_2"
|
299
|
+
ON "users"."id" = "users_2"."id"
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'takes a class' do
|
304
|
+
left = Table.new :users
|
305
|
+
right = left.alias
|
306
|
+
predicate = left[:id].eq(right[:id])
|
307
|
+
manager = Arel::SelectManager.new Table.engine
|
308
|
+
|
309
|
+
manager.from left
|
310
|
+
manager.join(right, Nodes::OuterJoin).on(predicate)
|
311
|
+
manager.to_sql.must_be_like %{
|
312
|
+
SELECT FROM "users"
|
313
|
+
LEFT OUTER JOIN "users" "users_2"
|
314
|
+
ON "users"."id" = "users_2"."id"
|
315
|
+
}
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'noops on nil' do
|
319
|
+
manager = Arel::SelectManager.new Table.engine
|
320
|
+
manager.join(nil).must_equal manager
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
describe 'joins' do
|
325
|
+
it 'returns join sql' do
|
326
|
+
table = Table.new :users
|
327
|
+
aliaz = table.alias
|
328
|
+
manager = Arel::SelectManager.new Table.engine
|
329
|
+
manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
|
330
|
+
manager.join_sql.must_be_like %{
|
331
|
+
INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"
|
332
|
+
}
|
333
|
+
manager.joins(manager).must_equal manager.join_sql
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'returns outer join sql' do
|
337
|
+
table = Table.new :users
|
338
|
+
aliaz = table.alias
|
339
|
+
manager = Arel::SelectManager.new Table.engine
|
340
|
+
manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id]))
|
341
|
+
manager.join_sql.must_be_like %{
|
342
|
+
LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"
|
343
|
+
}
|
344
|
+
manager.joins(manager).must_equal manager.join_sql
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'returns string join sql' do
|
348
|
+
table = Table.new :users
|
349
|
+
manager = Arel::SelectManager.new Table.engine
|
350
|
+
manager.from Nodes::StringJoin.new(table, 'hello')
|
351
|
+
manager.join_sql.must_be_like %{ 'hello' }
|
352
|
+
manager.joins(manager).must_equal manager.join_sql
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'returns nil join sql' do
|
356
|
+
manager = Arel::SelectManager.new Table.engine
|
357
|
+
manager.join_sql.must_be_nil
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
describe 'order_clauses' do
|
362
|
+
it 'returns order clauses as a list' do
|
363
|
+
table = Table.new :users
|
364
|
+
manager = Arel::SelectManager.new Table.engine
|
365
|
+
manager.from table
|
366
|
+
manager.order table[:id]
|
367
|
+
manager.order_clauses.first.must_be_like %{ "users"."id" }
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe 'group' do
|
372
|
+
it 'takes an attribute' do
|
373
|
+
table = Table.new :users
|
374
|
+
manager = Arel::SelectManager.new Table.engine
|
375
|
+
manager.from table
|
376
|
+
manager.group table[:id]
|
377
|
+
manager.to_sql.must_be_like %{
|
378
|
+
SELECT FROM "users" GROUP BY "users"."id"
|
379
|
+
}
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'chains' do
|
383
|
+
table = Table.new :users
|
384
|
+
manager = Arel::SelectManager.new Table.engine
|
385
|
+
manager.group(table[:id]).must_equal manager
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'takes multiple args' do
|
389
|
+
table = Table.new :users
|
390
|
+
manager = Arel::SelectManager.new Table.engine
|
391
|
+
manager.from table
|
392
|
+
manager.group table[:id], table[:name]
|
393
|
+
manager.to_sql.must_be_like %{
|
394
|
+
SELECT FROM "users" GROUP BY "users"."id", "users"."name"
|
395
|
+
}
|
396
|
+
end
|
397
|
+
|
398
|
+
# FIXME: backwards compat
|
399
|
+
it 'makes strings literals' do
|
400
|
+
table = Table.new :users
|
401
|
+
manager = Arel::SelectManager.new Table.engine
|
402
|
+
manager.from table
|
403
|
+
manager.group 'foo'
|
404
|
+
manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo }
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe 'delete' do
|
409
|
+
it "copies from" do
|
410
|
+
engine = EngineProxy.new Table.engine
|
411
|
+
table = Table.new :users
|
412
|
+
manager = Arel::SelectManager.new engine
|
413
|
+
manager.from table
|
414
|
+
manager.delete
|
415
|
+
|
416
|
+
engine.executed.last.must_be_like %{ DELETE FROM "users" }
|
417
|
+
end
|
418
|
+
|
419
|
+
it "copies where" do
|
420
|
+
engine = EngineProxy.new Table.engine
|
421
|
+
table = Table.new :users
|
422
|
+
manager = Arel::SelectManager.new engine
|
423
|
+
manager.from table
|
424
|
+
manager.where table[:id].eq 10
|
425
|
+
manager.delete
|
426
|
+
|
427
|
+
engine.executed.last.must_be_like %{
|
428
|
+
DELETE FROM "users" WHERE "users"."id" = 10
|
429
|
+
}
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
describe 'where_sql' do
|
434
|
+
it 'gives me back the where sql' do
|
435
|
+
table = Table.new :users
|
436
|
+
manager = Arel::SelectManager.new Table.engine
|
437
|
+
manager.from table
|
438
|
+
manager.where table[:id].eq 10
|
439
|
+
manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 }
|
440
|
+
end
|
441
|
+
|
442
|
+
it 'returns nil when there are no wheres' do
|
443
|
+
table = Table.new :users
|
444
|
+
manager = Arel::SelectManager.new Table.engine
|
445
|
+
manager.from table
|
446
|
+
manager.where_sql.must_be_nil
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
describe 'update' do
|
451
|
+
it 'copies limits' do
|
452
|
+
engine = EngineProxy.new Table.engine
|
453
|
+
table = Table.new :users
|
454
|
+
manager = Arel::SelectManager.new engine
|
455
|
+
manager.from table
|
456
|
+
manager.take 1
|
457
|
+
manager.update(SqlLiteral.new('foo = bar'))
|
458
|
+
|
459
|
+
engine.executed.last.must_be_like %{
|
460
|
+
UPDATE "users" SET foo = bar
|
461
|
+
WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1)
|
462
|
+
}
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'copies order' do
|
466
|
+
engine = EngineProxy.new Table.engine
|
467
|
+
table = Table.new :users
|
468
|
+
manager = Arel::SelectManager.new engine
|
469
|
+
manager.from table
|
470
|
+
manager.order :foo
|
471
|
+
manager.update(SqlLiteral.new('foo = bar'))
|
472
|
+
|
473
|
+
engine.executed.last.must_be_like %{
|
474
|
+
UPDATE "users" SET foo = bar
|
475
|
+
WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo)
|
476
|
+
}
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'takes a string' do
|
480
|
+
engine = EngineProxy.new Table.engine
|
481
|
+
table = Table.new :users
|
482
|
+
manager = Arel::SelectManager.new engine
|
483
|
+
manager.from table
|
484
|
+
manager.update(SqlLiteral.new('foo = bar'))
|
485
|
+
|
486
|
+
engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar }
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'copies where clauses' do
|
490
|
+
engine = EngineProxy.new Table.engine
|
491
|
+
table = Table.new :users
|
492
|
+
manager = Arel::SelectManager.new engine
|
493
|
+
manager.where table[:id].eq 10
|
494
|
+
manager.from table
|
495
|
+
manager.update(table[:id] => 1)
|
496
|
+
|
497
|
+
engine.executed.last.must_be_like %{
|
498
|
+
UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10
|
499
|
+
}
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'executes an update statement' do
|
503
|
+
engine = EngineProxy.new Table.engine
|
504
|
+
table = Table.new :users
|
505
|
+
manager = Arel::SelectManager.new engine
|
506
|
+
manager.from table
|
507
|
+
manager.update(table[:id] => 1)
|
508
|
+
|
509
|
+
engine.executed.last.must_be_like %{
|
510
|
+
UPDATE "users" SET "id" = 1
|
511
|
+
}
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
describe 'project' do
|
516
|
+
it 'takes multiple args' do
|
517
|
+
manager = Arel::SelectManager.new Table.engine
|
518
|
+
manager.project Nodes::SqlLiteral.new('foo'),
|
519
|
+
Nodes::SqlLiteral.new('bar')
|
520
|
+
manager.to_sql.must_be_like %{ SELECT foo, bar }
|
521
|
+
end
|
522
|
+
|
523
|
+
it 'takes strings' do
|
524
|
+
manager = Arel::SelectManager.new Table.engine
|
525
|
+
manager.project Nodes::SqlLiteral.new('*')
|
526
|
+
manager.to_sql.must_be_like %{ SELECT * }
|
527
|
+
end
|
528
|
+
|
529
|
+
it "takes sql literals" do
|
530
|
+
manager = Arel::SelectManager.new Table.engine
|
531
|
+
manager.project Nodes::SqlLiteral.new '*'
|
532
|
+
manager.to_sql.must_be_like %{
|
533
|
+
SELECT *
|
534
|
+
}
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
describe 'take' do
|
539
|
+
it "knows take" do
|
540
|
+
table = Table.new :users
|
541
|
+
manager = Arel::SelectManager.new Table.engine
|
542
|
+
manager.from(table).project(table['id'])
|
543
|
+
manager.where(table['id'].eq(1))
|
544
|
+
manager.take 1
|
545
|
+
|
546
|
+
manager.to_sql.must_be_like %{
|
547
|
+
SELECT "users"."id"
|
548
|
+
FROM "users"
|
549
|
+
WHERE "users"."id" = 1
|
550
|
+
LIMIT 1
|
551
|
+
}
|
552
|
+
end
|
553
|
+
|
554
|
+
it "chains" do
|
555
|
+
manager = Arel::SelectManager.new Table.engine
|
556
|
+
manager.take(1).must_equal manager
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
describe 'where' do
|
561
|
+
it "knows where" do
|
562
|
+
table = Table.new :users
|
563
|
+
manager = Arel::SelectManager.new Table.engine
|
564
|
+
manager.from(table).project(table['id'])
|
565
|
+
manager.where(table['id'].eq(1))
|
566
|
+
manager.to_sql.must_be_like %{
|
567
|
+
SELECT "users"."id"
|
568
|
+
FROM "users"
|
569
|
+
WHERE "users"."id" = 1
|
570
|
+
}
|
571
|
+
end
|
572
|
+
|
573
|
+
it "chains" do
|
574
|
+
table = Table.new :users
|
575
|
+
manager = Arel::SelectManager.new Table.engine
|
576
|
+
manager.from(table)
|
577
|
+
manager.project(table['id']).where(table['id'].eq 1).must_equal manager
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
describe "join" do
|
582
|
+
it "joins itself" do
|
583
|
+
left = Table.new :users
|
584
|
+
right = left.alias
|
585
|
+
predicate = left[:id].eq(right[:id])
|
586
|
+
|
587
|
+
mgr = left.join(right)
|
588
|
+
mgr.project Nodes::SqlLiteral.new('*')
|
589
|
+
mgr.on(predicate).must_equal mgr
|
590
|
+
|
591
|
+
mgr.to_sql.must_be_like %{
|
592
|
+
SELECT * FROM "users"
|
593
|
+
INNER JOIN "users" "users_2"
|
594
|
+
ON "users"."id" = "users_2"."id"
|
595
|
+
}
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
describe 'from' do
|
600
|
+
it "makes sql" do
|
601
|
+
table = Table.new :users
|
602
|
+
manager = Arel::SelectManager.new Table.engine
|
603
|
+
|
604
|
+
manager.from table
|
605
|
+
manager.project table['id']
|
606
|
+
manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
|
607
|
+
end
|
608
|
+
|
609
|
+
it "chains" do
|
610
|
+
table = Table.new :users
|
611
|
+
manager = Arel::SelectManager.new Table.engine
|
612
|
+
manager.from(table).project(table['id']).must_equal manager
|
613
|
+
manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"'
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
describe 'set operations' do
|
619
|
+
before do
|
620
|
+
@table = Table.new :users
|
621
|
+
@m1 = Arel::SelectManager.new Table.engine, @table
|
622
|
+
@m1.project Arel.sql('*')
|
623
|
+
@m2 = Arel::SelectManager.new Table.engine, @table
|
624
|
+
@m2.project Arel.sql('*')
|
625
|
+
end
|
626
|
+
|
627
|
+
it 'supports union' do
|
628
|
+
@m1.where(@table[:id].lt(18))
|
629
|
+
@m2.where(@table[:id].gt(99))
|
630
|
+
(@m1.union @m2).to_sql.must_be_like %{
|
631
|
+
( SELECT * FROM "users" WHERE "users"."id" < 18 UNION SELECT * FROM "users" WHERE "users"."id" > 99 )
|
632
|
+
}
|
633
|
+
end
|
634
|
+
|
635
|
+
it 'supports union all' do
|
636
|
+
@m1.where(@table[:id].lt(18))
|
637
|
+
@m2.where(@table[:id].gt(99))
|
638
|
+
(@m1.union :all, @m2).to_sql.must_be_like %{
|
639
|
+
( SELECT * FROM "users" WHERE "users"."id" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."id" > 99 )
|
640
|
+
}
|
641
|
+
end
|
642
|
+
|
643
|
+
it 'supports intersect' do
|
644
|
+
@m1.where(@table[:id].gt(18))
|
645
|
+
@m2.where(@table[:id].lt(99))
|
646
|
+
(@m1.intersect @m2).to_sql.must_be_like %{
|
647
|
+
( SELECT * FROM "users" WHERE "users"."id" > 18 INTERSECT SELECT * FROM "users" WHERE "users"."id" < 99 )
|
648
|
+
}
|
649
|
+
end
|
650
|
+
|
651
|
+
it 'supports except' do
|
652
|
+
@m1.where(@table[:id].in(18..60))
|
653
|
+
@m2.where(@table[:id].in(40..99))
|
654
|
+
(@m1.except @m2).to_sql.must_be_like %{
|
655
|
+
( SELECT * FROM "users" WHERE "users"."id" BETWEEN 18 AND 60 EXCEPT SELECT * FROM "users" WHERE "users"."id" BETWEEN 40 AND 99 )
|
656
|
+
}
|
657
|
+
end
|
658
|
+
end
|
659
|
+
end
|