arel 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +26 -0
- data/History.txt +18 -0
- data/Manifest.txt +31 -30
- data/README.markdown +7 -99
- data/Rakefile +3 -2
- data/arel.gemspec +18 -11
- data/lib/arel.rb +2 -1
- data/lib/arel/attributes/attribute.rb +1 -174
- data/lib/arel/crud.rb +2 -2
- data/lib/arel/delete_manager.rb +4 -4
- data/lib/arel/insert_manager.rb +8 -8
- data/lib/arel/nodes/exists.rb +2 -6
- data/lib/arel/nodes/sql_literal.rb +1 -0
- data/lib/arel/predications.rb +177 -0
- data/lib/arel/select_manager.rb +17 -11
- data/lib/arel/table.rb +4 -0
- data/lib/arel/tree_manager.rb +4 -3
- data/lib/arel/update_manager.rb +8 -8
- data/lib/arel/visitors.rb +4 -0
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/join_sql.rb +2 -0
- data/lib/arel/visitors/mysql.rb +14 -0
- data/lib/arel/visitors/oracle.rb +31 -1
- data/lib/arel/visitors/order_clauses.rb +2 -0
- data/lib/arel/visitors/sqlite.rb +11 -0
- data/lib/arel/visitors/to_sql.rb +8 -11
- data/lib/arel/visitors/visitor.rb +19 -0
- data/{spec/attributes/attribute_spec.rb → test/attributes/test_attribute.rb} +84 -84
- data/test/helper.rb +13 -0
- data/{spec/nodes/count_spec.rb → test/nodes/test_count.rb} +3 -3
- data/{spec/nodes/delete_statement_spec.rb → test/nodes/test_delete_statement.rb} +3 -4
- data/{spec/nodes/equality_spec.rb → test/nodes/test_equality.rb} +10 -8
- data/{spec/nodes/insert_statement_spec.rb → test/nodes/test_insert_statement.rb} +6 -6
- data/{spec/nodes/or_spec.rb → test/nodes/test_or.rb} +6 -4
- data/test/nodes/test_select_core.rb +22 -0
- data/{spec/nodes/select_statement_spec.rb → test/nodes/test_select_statement.rb} +3 -4
- data/test/nodes/test_sql_literal.rb +52 -0
- data/{spec/nodes/sum_spec.rb → test/nodes/test_sum.rb} +2 -2
- data/{spec/nodes/update_statement_spec.rb → test/nodes/test_update_statement.rb} +6 -6
- data/{spec → test}/support/fake_record.rb +4 -2
- data/{spec/activerecord_compat_spec.rb → test/test_activerecord_compat.rb} +3 -3
- data/{spec/attributes_spec.rb → test/test_attributes.rb} +7 -7
- data/{spec/crud_spec.rb → test/test_crud.rb} +4 -4
- data/{spec/delete_manager_spec.rb → test/test_delete_manager.rb} +5 -16
- data/{spec/insert_manager_spec.rb → test/test_insert_manager.rb} +15 -31
- data/{spec/select_manager_spec.rb → test/test_select_manager.rb} +95 -77
- data/{spec/table_spec.rb → test/test_table.rb} +38 -32
- data/{spec/update_manager_spec.rb → test/test_update_manager.rb} +9 -21
- data/{spec/visitors/join_sql_spec.rb → test/visitors/test_join_sql.rb} +3 -3
- data/test/visitors/test_mysql.rb +27 -0
- data/{spec/visitors/oracle_spec.rb → test/visitors/test_oracle.rb} +26 -10
- data/{spec/visitors/postgres_spec.rb → test/visitors/test_postgres.rb} +2 -2
- data/test/visitors/test_sqlite.rb +18 -0
- data/{spec/visitors/to_sql_spec.rb → test/visitors/test_to_sql.rb} +25 -18
- metadata +101 -43
- data/spec/nodes/select_core_spec.rb +0 -21
- data/spec/nodes/sql_literal_spec.rb +0 -26
- data/spec/spec.opts +0 -3
- data/spec/spec_helper.rb +0 -18
- data/spec/support/check.rb +0 -6
- data/spec/support/matchers.rb +0 -4
- data/spec/support/matchers/be_like.rb +0 -24
- data/spec/support/shared/tree_manager_shared.rb +0 -9
data/.autotest
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
# require 'autotest/restart'
|
4
|
+
|
5
|
+
ENV['GEM_PATH'] = "tmp/isolate/ruby-1.8"
|
6
|
+
|
7
|
+
module Autotest::Restart
|
8
|
+
Autotest.add_hook :updated do |at, *args|
|
9
|
+
if args.flatten.include? ".autotest" then
|
10
|
+
warn "Detected change to .autotest, restarting"
|
11
|
+
cmd = %w(autotest)
|
12
|
+
cmd << " -v" if $v
|
13
|
+
cmd += ARGV
|
14
|
+
|
15
|
+
exec(*cmd)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Autotest.add_hook :initialize do |at|
|
21
|
+
at.add_exception 'tmp'
|
22
|
+
at.testlib = "minitest/autorun"
|
23
|
+
|
24
|
+
at.find_directories = ARGV unless ARGV.empty?
|
25
|
+
end
|
26
|
+
|
data/History.txt
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
== 2.0.2
|
2
|
+
|
3
|
+
* Bug fixes
|
4
|
+
|
5
|
+
* MySQL selects from DUAL on empty FROM
|
6
|
+
* Visitor translates nil to NULL
|
7
|
+
* Visitor translates Bignum properly
|
8
|
+
|
9
|
+
== 2.0.1
|
10
|
+
|
11
|
+
* Bug fixes
|
12
|
+
|
13
|
+
== 2.0.0 / 2010-08-01
|
14
|
+
* Enhancements
|
15
|
+
|
16
|
+
* Recreate library using the Visitor pattern.
|
17
|
+
http://en.wikipedia.org/wiki/Visitor_pattern
|
18
|
+
|
1
19
|
== 0.3.0 / 2010-03-10
|
2
20
|
|
3
21
|
* Enhancements
|
data/Manifest.txt
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
.autotest
|
1
2
|
History.txt
|
2
3
|
MIT-LICENSE.txt
|
3
4
|
Manifest.txt
|
@@ -58,6 +59,7 @@ lib/arel/nodes/table_alias.rb
|
|
58
59
|
lib/arel/nodes/unqualified_column.rb
|
59
60
|
lib/arel/nodes/update_statement.rb
|
60
61
|
lib/arel/nodes/values.rb
|
62
|
+
lib/arel/predications.rb
|
61
63
|
lib/arel/relation.rb
|
62
64
|
lib/arel/select_manager.rb
|
63
65
|
lib/arel/sql/engine.rb
|
@@ -72,35 +74,34 @@ lib/arel/visitors/mysql.rb
|
|
72
74
|
lib/arel/visitors/oracle.rb
|
73
75
|
lib/arel/visitors/order_clauses.rb
|
74
76
|
lib/arel/visitors/postgresql.rb
|
77
|
+
lib/arel/visitors/sqlite.rb
|
75
78
|
lib/arel/visitors/to_sql.rb
|
79
|
+
lib/arel/visitors/visitor.rb
|
76
80
|
lib/arel/visitors/where_sql.rb
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
spec/visitors/oracle_spec.rb
|
105
|
-
spec/visitors/postgres_spec.rb
|
106
|
-
spec/visitors/to_sql_spec.rb
|
81
|
+
test/attributes/test_attribute.rb
|
82
|
+
test/helper.rb
|
83
|
+
test/nodes/test_count.rb
|
84
|
+
test/nodes/test_delete_statement.rb
|
85
|
+
test/nodes/test_equality.rb
|
86
|
+
test/nodes/test_insert_statement.rb
|
87
|
+
test/nodes/test_or.rb
|
88
|
+
test/nodes/test_select_core.rb
|
89
|
+
test/nodes/test_select_statement.rb
|
90
|
+
test/nodes/test_sql_literal.rb
|
91
|
+
test/nodes/test_sum.rb
|
92
|
+
test/nodes/test_update_statement.rb
|
93
|
+
test/support/fake_record.rb
|
94
|
+
test/test_activerecord_compat.rb
|
95
|
+
test/test_attributes.rb
|
96
|
+
test/test_crud.rb
|
97
|
+
test/test_delete_manager.rb
|
98
|
+
test/test_insert_manager.rb
|
99
|
+
test/test_select_manager.rb
|
100
|
+
test/test_table.rb
|
101
|
+
test/test_update_manager.rb
|
102
|
+
test/visitors/test_join_sql.rb
|
103
|
+
test/visitors/test_mysql.rb
|
104
|
+
test/visitors/test_oracle.rb
|
105
|
+
test/visitors/test_postgres.rb
|
106
|
+
test/visitors/test_sqlite.rb
|
107
|
+
test/visitors/test_to_sql.rb
|
data/README.markdown
CHANGED
@@ -8,9 +8,7 @@ Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex o
|
|
8
8
|
|
9
9
|
## Status
|
10
10
|
|
11
|
-
For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion.
|
12
|
-
|
13
|
-
The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc.
|
11
|
+
For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion.
|
14
12
|
|
15
13
|
## A Gentle Introduction
|
16
14
|
|
@@ -20,19 +18,10 @@ Generating a query with ARel is simple. For example, in order to produce
|
|
20
18
|
|
21
19
|
you construct a table relation and convert it to sql:
|
22
20
|
|
23
|
-
users = Table(:users)
|
21
|
+
users = Arel::Table.new(:users)
|
22
|
+
users.project(Arel.sql('*'))
|
24
23
|
users.to_sql
|
25
24
|
|
26
|
-
In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this:
|
27
|
-
|
28
|
-
users.each { |user| ... }
|
29
|
-
|
30
|
-
In other words, Arel relations implement Ruby's Enumerable interface. Let's have a look at a concrete example:
|
31
|
-
|
32
|
-
users.first # => { users[:id] => 1, users[:name] => 'bob' }
|
33
|
-
|
34
|
-
As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth).
|
35
|
-
|
36
25
|
### More Sophisticated Queries
|
37
26
|
|
38
27
|
Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database.
|
@@ -75,19 +64,11 @@ Of course, many of the operators take multiple arguments, so the last example ca
|
|
75
64
|
|
76
65
|
users.where(users[:name].eq('bob'), users[:age].lt(25))
|
77
66
|
|
78
|
-
The `OR` operator
|
67
|
+
The `OR` operator works like this:
|
79
68
|
|
80
69
|
users.where(users[:name].eq('bob').or(users[:age].lt(25)))
|
81
70
|
|
82
|
-
The `AND` operator
|
83
|
-
|
84
|
-
Finally, most operations take a block form. For example:
|
85
|
-
|
86
|
-
Table(:users) \
|
87
|
-
.where { |u| u[:id].eq(1) } \
|
88
|
-
.project { |u| u[:id] }
|
89
|
-
|
90
|
-
This provides a (sometimes) convenient alternative syntax.
|
71
|
+
The `AND` operator behaves similarly.
|
91
72
|
|
92
73
|
### The Crazy Features
|
93
74
|
|
@@ -97,11 +78,11 @@ The examples above are fairly simple and other libraries match or come close to
|
|
97
78
|
|
98
79
|
Where Arel really shines in its ability to handle complex joins and aggregations. As a first example, let's consider an "adjacency list", a tree represented in a table. Suppose we have a table `comments`, representing a threaded discussion:
|
99
80
|
|
100
|
-
comments = Table(:comments)
|
81
|
+
comments = Arel::Table.new(:comments)
|
101
82
|
|
102
83
|
And this table has the following attributes:
|
103
84
|
|
104
|
-
comments.
|
85
|
+
comments.columns # => [comments[:id], comments[:body], comments[:parent_id]]
|
105
86
|
|
106
87
|
The `parent_id` column is a foreign key from the `comments` table to itself. Now, joining a table to itself requires aliasing in SQL. In fact, you may alias in Arel as well:
|
107
88
|
|
@@ -110,77 +91,4 @@ The `parent_id` column is a foreign key from the `comments` table to itself. Now
|
|
110
91
|
comments.join(replies).on(replies[:parent_id].eq(comments[:id]))
|
111
92
|
# => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id
|
112
93
|
|
113
|
-
The call to `#alias` is actually optional: Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Explicit aliasing is more common, however. When you want to extract specific slices of data, aliased tables are a necessity. For example to get just certain columns from the row, treat a row like a hash:
|
114
|
-
|
115
|
-
comments_with_replies.first[replies[:body]]
|
116
|
-
|
117
94
|
This will return the first comment's reply's body.
|
118
|
-
|
119
|
-
If you don't need to extract the data later (for example, you're simply doing a join to find comments that have replies, you don't care what the content of the replies are), the block form may be preferable:
|
120
|
-
|
121
|
-
comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) }
|
122
|
-
# => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id
|
123
|
-
|
124
|
-
Note that you do NOT want to do something like:
|
125
|
-
|
126
|
-
comments.join(comments, comments[:parent_id].eq(comments[:id]))
|
127
|
-
# => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id
|
128
|
-
|
129
|
-
This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous.
|
130
|
-
|
131
|
-
#### Complex Aggregations
|
132
|
-
|
133
|
-
My personal favorite feature of Arel, certainly the most difficult to implement, and possibly only of marginal value, is **closure under joining even in the presence of aggregations**. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. Think of this as a preview of the kind of radical functionality that is to come, stuff no other "ORM" is doing.
|
134
|
-
|
135
|
-
The easiest way to introduce this is in SQL. Your task is to get all users and the **count** of their associated photos. Let's start from the inside out:
|
136
|
-
|
137
|
-
SELECT count(*)
|
138
|
-
FROM photos
|
139
|
-
GROUP BY user_id
|
140
|
-
|
141
|
-
Now, we'd like to join this with the user table. Naively, you might try to do this:
|
142
|
-
|
143
|
-
SELECT users.*, count(photos.id)
|
144
|
-
FROM users
|
145
|
-
LEFT OUTER JOIN photos
|
146
|
-
ON users.id = photos.user_id
|
147
|
-
GROUP BY photos.user_id
|
148
|
-
|
149
|
-
Of course, this has a slightly different meaning than our intended query. This is actually a fairly advanced topic in SQL so let's see why this doesn't work *step by step*. Suppose we have these records in our `users` table:
|
150
|
-
|
151
|
-
mysql> select * from users;
|
152
|
-
+------+--------+
|
153
|
-
| id | name |
|
154
|
-
+------+--------+
|
155
|
-
| 1 | hai |
|
156
|
-
| 2 | bai |
|
157
|
-
| 3 | dumpty |
|
158
|
-
+------+--------+
|
159
|
-
|
160
|
-
And these in the photos table:
|
161
|
-
|
162
|
-
mysql> select * from photos;
|
163
|
-
+------+---------+-----------+
|
164
|
-
| id | user_id | camera_id |
|
165
|
-
+------+---------+-----------+
|
166
|
-
| 1 | 1 | 1 |
|
167
|
-
| 2 | 1 | 1 |
|
168
|
-
| 3 | 1 | 1 |
|
169
|
-
+------+---------+-----------+
|
170
|
-
|
171
|
-
If we perform the above, incorrect query, we get the following:
|
172
|
-
|
173
|
-
mysql> select users.*, count(photos.id) from users left outer join photos on users.id = photos.user_id limit 3 group by user_id;
|
174
|
-
+------+------+------------------+
|
175
|
-
| id | name | count(photos.id) |
|
176
|
-
+------+------+------------------+
|
177
|
-
| 2 | bai | 0 |
|
178
|
-
| 1 | hai | 3 |
|
179
|
-
+------+------+------------------+
|
180
|
-
|
181
|
-
As you can see, we're completely missing data for user with id 3. `dumpty` has no photos, neither does `bai`. But strangely `bai` appeared and `dumpty` didn't! The reason is that the `GROUP BY` clause is aggregating on both tables, not just the `photos` table. All users without photos have a `photos.id` of `null` (thanks to the left outer join). These are rolled up together and an arbitrary user wins. In this case, `bai` not `dumpty`.
|
182
|
-
|
183
|
-
SELECT users.*, photos_aggregation.cnt
|
184
|
-
FROM users
|
185
|
-
LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation
|
186
|
-
ON photos_aggregation.user_id = users.id
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@ require "rubygems"
|
|
2
2
|
gem 'hoe', '>= 2.1.0'
|
3
3
|
require 'hoe'
|
4
4
|
|
5
|
+
Hoe.plugin :minitest
|
5
6
|
Hoe.plugin :gemspec # `gem install hoe-gemspec`
|
6
7
|
|
7
8
|
Hoe.spec 'arel' do
|
@@ -12,6 +13,6 @@ Hoe.spec 'arel' do
|
|
12
13
|
|
13
14
|
self.readme_file = 'README.markdown'
|
14
15
|
self.extra_rdoc_files = FileList['README.markdown']
|
15
|
-
self.extra_dev_deps << ['
|
16
|
-
self.
|
16
|
+
self.extra_dev_deps << [ 'hoe', '>= 2.1.0' ]
|
17
|
+
self.extra_dev_deps << [ 'minitest', '>= 1.6.0' ]
|
17
18
|
end
|
data/arel.gemspec
CHANGED
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{arel}
|
5
|
-
s.version = "2.0.
|
5
|
+
s.version = "2.0.1.20101111105523"
|
6
6
|
|
7
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"]
|
9
|
-
s.date = %q{2010-
|
9
|
+
s.date = %q{2010-11-11}
|
10
10
|
s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 2) adapts to various RDBMS systems. It is intended to be a framework framework; that is, you can build your own ORM with it, focusing on innovative object and collection modeling as opposed to database compatibility and query generation.}
|
11
11
|
s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"]
|
12
|
-
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.markdown"]
|
13
|
-
s.files = ["History.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/deprecated.rb", "lib/arel/expression.rb", "lib/arel/expressions.rb", "lib/arel/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.rb", "lib/arel/select_manager.rb", "lib/arel/sql/engine.rb", "lib/arel/sql_literal.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/order_clauses.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/
|
12
|
+
s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"]
|
13
|
+
s.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/deprecated.rb", "lib/arel/expression.rb", "lib/arel/expressions.rb", "lib/arel/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/predications.rb", "lib/arel/relation.rb", "lib/arel/select_manager.rb", "lib/arel/sql/engine.rb", "lib/arel/sql_literal.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/order_clauses.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.rb", "test/support/fake_record.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"]
|
14
14
|
s.homepage = %q{http://github.com/rails/arel}
|
15
15
|
s.rdoc_options = ["--main", "README.markdown"]
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.rubyforge_project = %q{arel}
|
18
18
|
s.rubygems_version = %q{1.3.7}
|
19
19
|
s.summary = %q{Arel is a Relational Algebra for Ruby}
|
20
|
+
s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"]
|
20
21
|
|
21
22
|
if s.respond_to? :specification_version then
|
22
23
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -24,16 +25,22 @@ Gem::Specification.new do |s|
|
|
24
25
|
|
25
26
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
26
27
|
s.add_development_dependency(%q<rubyforge>, [">= 2.0.4"])
|
27
|
-
s.add_development_dependency(%q<
|
28
|
-
s.add_development_dependency(%q<hoe>, [">= 2.
|
28
|
+
s.add_development_dependency(%q<minitest>, [">= 2.0.0.beta"])
|
29
|
+
s.add_development_dependency(%q<hoe>, [">= 2.1.0"])
|
30
|
+
s.add_development_dependency(%q<minitest>, [">= 1.6.0"])
|
31
|
+
s.add_development_dependency(%q<hoe>, [">= 2.6.2"])
|
29
32
|
else
|
30
33
|
s.add_dependency(%q<rubyforge>, [">= 2.0.4"])
|
31
|
-
s.add_dependency(%q<
|
32
|
-
s.add_dependency(%q<hoe>, [">= 2.
|
34
|
+
s.add_dependency(%q<minitest>, [">= 2.0.0.beta"])
|
35
|
+
s.add_dependency(%q<hoe>, [">= 2.1.0"])
|
36
|
+
s.add_dependency(%q<minitest>, [">= 1.6.0"])
|
37
|
+
s.add_dependency(%q<hoe>, [">= 2.6.2"])
|
33
38
|
end
|
34
39
|
else
|
35
40
|
s.add_dependency(%q<rubyforge>, [">= 2.0.4"])
|
36
|
-
s.add_dependency(%q<
|
37
|
-
s.add_dependency(%q<hoe>, [">= 2.
|
41
|
+
s.add_dependency(%q<minitest>, [">= 2.0.0.beta"])
|
42
|
+
s.add_dependency(%q<hoe>, [">= 2.1.0"])
|
43
|
+
s.add_dependency(%q<minitest>, [">= 1.6.0"])
|
44
|
+
s.add_dependency(%q<hoe>, [">= 2.6.2"])
|
38
45
|
end
|
39
46
|
end
|
data/lib/arel.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'arel/crud'
|
2
2
|
|
3
3
|
require 'arel/expressions'
|
4
|
+
require 'arel/predications'
|
4
5
|
require 'arel/table'
|
5
6
|
require 'arel/attributes'
|
6
7
|
require 'arel/compatibility/wheres'
|
@@ -27,7 +28,7 @@ require 'arel/sql_literal'
|
|
27
28
|
####
|
28
29
|
|
29
30
|
module Arel
|
30
|
-
VERSION = '2.0.
|
31
|
+
VERSION = '2.0.2'
|
31
32
|
|
32
33
|
def self.sql raw_sql
|
33
34
|
Arel::Nodes::SqlLiteral.new raw_sql
|
@@ -2,180 +2,7 @@ module Arel
|
|
2
2
|
module Attributes
|
3
3
|
class Attribute < Struct.new :relation, :name, :column
|
4
4
|
include Arel::Expressions
|
5
|
-
|
6
|
-
def not_eq other
|
7
|
-
Nodes::NotEqual.new self, other
|
8
|
-
end
|
9
|
-
|
10
|
-
def not_eq_any others
|
11
|
-
grouping_any :not_eq, others
|
12
|
-
end
|
13
|
-
|
14
|
-
def not_eq_all others
|
15
|
-
grouping_all :not_eq, others
|
16
|
-
end
|
17
|
-
|
18
|
-
def eq other
|
19
|
-
Nodes::Equality.new self, other
|
20
|
-
end
|
21
|
-
|
22
|
-
def eq_any others
|
23
|
-
grouping_any :eq, others
|
24
|
-
end
|
25
|
-
|
26
|
-
def eq_all others
|
27
|
-
grouping_all :eq, others
|
28
|
-
end
|
29
|
-
|
30
|
-
def in other
|
31
|
-
case other
|
32
|
-
when Arel::SelectManager
|
33
|
-
Nodes::In.new self, other.to_a.map { |x| x.id }
|
34
|
-
when Range
|
35
|
-
if other.exclude_end?
|
36
|
-
left = Nodes::GreaterThanOrEqual.new(self, other.min)
|
37
|
-
right = Nodes::LessThan.new(self, other.max + 1)
|
38
|
-
Nodes::And.new left, right
|
39
|
-
else
|
40
|
-
Nodes::Between.new(self, Nodes::And.new(other.min, other.max))
|
41
|
-
end
|
42
|
-
else
|
43
|
-
Nodes::In.new self, other
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def in_any others
|
48
|
-
grouping_any :in, others
|
49
|
-
end
|
50
|
-
|
51
|
-
def in_all others
|
52
|
-
grouping_all :in, others
|
53
|
-
end
|
54
|
-
|
55
|
-
def not_in other
|
56
|
-
case other
|
57
|
-
when Arel::SelectManager
|
58
|
-
Nodes::NotIn.new self, other.to_a.map { |x| x.id }
|
59
|
-
when Range
|
60
|
-
if other.exclude_end?
|
61
|
-
left = Nodes::LessThan.new(self, other.min)
|
62
|
-
right = Nodes::GreaterThanOrEqual.new(self, other.max)
|
63
|
-
Nodes::Or.new left, right
|
64
|
-
else
|
65
|
-
left = Nodes::LessThan.new(self, other.min)
|
66
|
-
right = Nodes::GreaterThan.new(self, other.max)
|
67
|
-
Nodes::Or.new left, right
|
68
|
-
end
|
69
|
-
else
|
70
|
-
Nodes::NotIn.new self, other
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def not_in_any others
|
75
|
-
grouping_any :not_in, others
|
76
|
-
end
|
77
|
-
|
78
|
-
def not_in_all others
|
79
|
-
grouping_all :not_in, others
|
80
|
-
end
|
81
|
-
|
82
|
-
def matches other
|
83
|
-
Nodes::Matches.new self, other
|
84
|
-
end
|
85
|
-
|
86
|
-
def matches_any others
|
87
|
-
grouping_any :matches, others
|
88
|
-
end
|
89
|
-
|
90
|
-
def matches_all others
|
91
|
-
grouping_all :matches, others
|
92
|
-
end
|
93
|
-
|
94
|
-
def does_not_match other
|
95
|
-
Nodes::DoesNotMatch.new self, other
|
96
|
-
end
|
97
|
-
|
98
|
-
def does_not_match_any others
|
99
|
-
grouping_any :does_not_match, others
|
100
|
-
end
|
101
|
-
|
102
|
-
def does_not_match_all others
|
103
|
-
grouping_all :does_not_match, others
|
104
|
-
end
|
105
|
-
|
106
|
-
def gteq right
|
107
|
-
Nodes::GreaterThanOrEqual.new self, right
|
108
|
-
end
|
109
|
-
|
110
|
-
def gteq_any others
|
111
|
-
grouping_any :gteq, others
|
112
|
-
end
|
113
|
-
|
114
|
-
def gteq_all others
|
115
|
-
grouping_all :gteq, others
|
116
|
-
end
|
117
|
-
|
118
|
-
def gt right
|
119
|
-
Nodes::GreaterThan.new self, right
|
120
|
-
end
|
121
|
-
|
122
|
-
def gt_any others
|
123
|
-
grouping_any :gt, others
|
124
|
-
end
|
125
|
-
|
126
|
-
def gt_all others
|
127
|
-
grouping_all :gt, others
|
128
|
-
end
|
129
|
-
|
130
|
-
def lt right
|
131
|
-
Nodes::LessThan.new self, right
|
132
|
-
end
|
133
|
-
|
134
|
-
def lt_any others
|
135
|
-
grouping_any :lt, others
|
136
|
-
end
|
137
|
-
|
138
|
-
def lt_all others
|
139
|
-
grouping_all :lt, others
|
140
|
-
end
|
141
|
-
|
142
|
-
def lteq right
|
143
|
-
Nodes::LessThanOrEqual.new self, right
|
144
|
-
end
|
145
|
-
|
146
|
-
def lteq_any others
|
147
|
-
grouping_any :lteq, others
|
148
|
-
end
|
149
|
-
|
150
|
-
def lteq_all others
|
151
|
-
grouping_all :lteq, others
|
152
|
-
end
|
153
|
-
|
154
|
-
def asc
|
155
|
-
Nodes::Ordering.new self, :asc
|
156
|
-
end
|
157
|
-
|
158
|
-
def desc
|
159
|
-
Nodes::Ordering.new self, :desc
|
160
|
-
end
|
161
|
-
|
162
|
-
private
|
163
|
-
|
164
|
-
def grouping_any method_id, others
|
165
|
-
first = send method_id, others.shift
|
166
|
-
|
167
|
-
Nodes::Grouping.new others.inject(first) { |memo,expr|
|
168
|
-
Nodes::Or.new(memo, send(method_id, expr))
|
169
|
-
}
|
170
|
-
end
|
171
|
-
|
172
|
-
def grouping_all method_id, others
|
173
|
-
first = send method_id, others.shift
|
174
|
-
|
175
|
-
Nodes::Grouping.new others.inject(first) { |memo,expr|
|
176
|
-
Nodes::And.new(memo, send(method_id, expr))
|
177
|
-
}
|
178
|
-
end
|
5
|
+
include Arel::Predications
|
179
6
|
end
|
180
7
|
|
181
8
|
class String < Attribute; end
|