arel 0.1.2 → 0.2.pre
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/History.txt +11 -0
- data/Rakefile +1 -1
- data/Thorfile +3 -1
- data/arel.gemspec +14 -3
- data/lib/arel.rb +1 -4
- data/lib/arel/algebra/relations.rb +3 -0
- data/lib/arel/algebra/relations/operations/from.rb +6 -0
- data/lib/arel/algebra/relations/operations/having.rb +13 -0
- data/lib/arel/algebra/relations/operations/lock.rb +12 -0
- data/lib/arel/algebra/relations/operations/project.rb +1 -1
- data/lib/arel/algebra/relations/relation.rb +8 -1
- data/lib/arel/algebra/relations/utilities/compound.rb +2 -2
- data/lib/arel/engines/memory/relations/operations.rb +6 -0
- data/lib/arel/engines/sql/christener.rb +2 -1
- data/lib/arel/engines/sql/formatters.rb +6 -0
- data/lib/arel/engines/sql/relations/relation.rb +20 -8
- data/lib/arel/engines/sql/relations/table.rb +15 -3
- data/lib/arel/engines/sql/relations/utilities/compound.rb +1 -1
- data/lib/arel/engines/sql/relations/writes.rb +22 -6
- data/spec/arel/algebra/unit/predicates/binary_spec.rb +1 -1
- data/spec/arel/algebra/unit/predicates/equality_spec.rb +2 -2
- data/spec/arel/algebra/unit/relations/relation_spec.rb +5 -5
- data/spec/arel/algebra/unit/session/session_spec.rb +5 -5
- data/spec/arel/engines/sql/unit/predicates/binary_spec.rb +1 -1
- data/spec/arel/engines/sql/unit/predicates/equality_spec.rb +2 -2
- data/spec/arel/engines/sql/unit/predicates/in_spec.rb +1 -1
- data/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +3 -3
- data/spec/arel/engines/sql/unit/relations/from_spec.rb +50 -0
- data/spec/arel/engines/sql/unit/relations/having_spec.rb +36 -0
- data/spec/arel/engines/sql/unit/relations/join_spec.rb +54 -2
- data/spec/arel/engines/sql/unit/relations/lock_spec.rb +61 -0
- data/spec/arel/engines/sql/unit/relations/table_spec.rb +22 -2
- data/spec/schemas/mysql_schema.rb +7 -0
- data/spec/schemas/postgresql_schema.rb +7 -0
- data/spec/schemas/sqlite3_schema.rb +7 -0
- data/spec/spec_helper.rb +1 -1
- metadata +15 -4
data/History.txt
ADDED
data/Rakefile
CHANGED
@@ -36,7 +36,7 @@ else
|
|
36
36
|
end
|
37
37
|
|
38
38
|
desc "Run specs with mysql and sqlite3 database adapters (default)"
|
39
|
-
task :spec => ["
|
39
|
+
task :spec => ["spec:sqlite3", "spec:mysql", "spec:postgresql"]
|
40
40
|
|
41
41
|
desc "Default task is to run specs"
|
42
42
|
task :default => :spec
|
data/Thorfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "activerecord"
|
2
|
+
|
1
3
|
module GemHelpers
|
2
4
|
|
3
5
|
def generate_gemspec
|
@@ -30,7 +32,7 @@ and query generation.
|
|
30
32
|
s.test_files = normalize_files(Dir['spec/**/*.rb'] - repo.lib.ignored_files)
|
31
33
|
|
32
34
|
s.has_rdoc = true
|
33
|
-
s.extra_rdoc_files = %w[README.markdown]
|
35
|
+
s.extra_rdoc_files = %w[History.txt README.markdown]
|
34
36
|
|
35
37
|
# Arel required ActiveRecord, but we're not declaring it to avoid a
|
36
38
|
# circular dependency chain. The solution is for ActiveRecord to release
|
data/arel.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{arel}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.2.pre"
|
6
6
|
|
7
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Bryan Helmkamp", "Nick Kallen"]
|
9
|
-
s.date = %q{
|
9
|
+
s.date = %q{2010-01-08}
|
10
10
|
s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex
|
11
11
|
of SQL queries and it 2) adapts to various RDBMS systems. It is intended to be
|
12
12
|
a framework framework; that is, you can build your own ORM with it, focusing on
|
@@ -14,11 +14,13 @@ innovative object and collection modeling as opposed to database compatibility
|
|
14
14
|
and query generation.}
|
15
15
|
s.email = %q{bryan@brynary.com}
|
16
16
|
s.extra_rdoc_files = [
|
17
|
+
"History.txt",
|
17
18
|
"README.markdown"
|
18
19
|
]
|
19
20
|
s.files = [
|
20
21
|
".gitignore",
|
21
22
|
".gitmodules",
|
23
|
+
"History.txt",
|
22
24
|
"README.markdown",
|
23
25
|
"Rakefile",
|
24
26
|
"Thorfile",
|
@@ -38,8 +40,11 @@ and query generation.}
|
|
38
40
|
"lib/arel/algebra/predicates.rb",
|
39
41
|
"lib/arel/algebra/relations.rb",
|
40
42
|
"lib/arel/algebra/relations/operations/alias.rb",
|
43
|
+
"lib/arel/algebra/relations/operations/from.rb",
|
41
44
|
"lib/arel/algebra/relations/operations/group.rb",
|
45
|
+
"lib/arel/algebra/relations/operations/having.rb",
|
42
46
|
"lib/arel/algebra/relations/operations/join.rb",
|
47
|
+
"lib/arel/algebra/relations/operations/lock.rb",
|
43
48
|
"lib/arel/algebra/relations/operations/order.rb",
|
44
49
|
"lib/arel/algebra/relations/operations/project.rb",
|
45
50
|
"lib/arel/algebra/relations/operations/skip.rb",
|
@@ -127,9 +132,12 @@ and query generation.}
|
|
127
132
|
"spec/arel/engines/sql/unit/primitives/value_spec.rb",
|
128
133
|
"spec/arel/engines/sql/unit/relations/alias_spec.rb",
|
129
134
|
"spec/arel/engines/sql/unit/relations/delete_spec.rb",
|
135
|
+
"spec/arel/engines/sql/unit/relations/from_spec.rb",
|
130
136
|
"spec/arel/engines/sql/unit/relations/group_spec.rb",
|
137
|
+
"spec/arel/engines/sql/unit/relations/having_spec.rb",
|
131
138
|
"spec/arel/engines/sql/unit/relations/insert_spec.rb",
|
132
139
|
"spec/arel/engines/sql/unit/relations/join_spec.rb",
|
140
|
+
"spec/arel/engines/sql/unit/relations/lock_spec.rb",
|
133
141
|
"spec/arel/engines/sql/unit/relations/order_spec.rb",
|
134
142
|
"spec/arel/engines/sql/unit/relations/project_spec.rb",
|
135
143
|
"spec/arel/engines/sql/unit/relations/skip_spec.rb",
|
@@ -199,9 +207,12 @@ and query generation.}
|
|
199
207
|
"spec/arel/engines/sql/unit/primitives/value_spec.rb",
|
200
208
|
"spec/arel/engines/sql/unit/relations/alias_spec.rb",
|
201
209
|
"spec/arel/engines/sql/unit/relations/delete_spec.rb",
|
210
|
+
"spec/arel/engines/sql/unit/relations/from_spec.rb",
|
202
211
|
"spec/arel/engines/sql/unit/relations/group_spec.rb",
|
212
|
+
"spec/arel/engines/sql/unit/relations/having_spec.rb",
|
203
213
|
"spec/arel/engines/sql/unit/relations/insert_spec.rb",
|
204
214
|
"spec/arel/engines/sql/unit/relations/join_spec.rb",
|
215
|
+
"spec/arel/engines/sql/unit/relations/lock_spec.rb",
|
205
216
|
"spec/arel/engines/sql/unit/relations/order_spec.rb",
|
206
217
|
"spec/arel/engines/sql/unit/relations/project_spec.rb",
|
207
218
|
"spec/arel/engines/sql/unit/relations/skip_spec.rb",
|
data/lib/arel.rb
CHANGED
@@ -2,13 +2,10 @@ require 'active_support/inflector'
|
|
2
2
|
require 'active_support/core_ext/module/delegation'
|
3
3
|
require 'active_support/core_ext/class/attribute_accessors'
|
4
4
|
|
5
|
-
require 'active_record'
|
6
|
-
require 'active_record/connection_adapters/abstract/quoting'
|
7
|
-
|
8
5
|
module Arel
|
9
6
|
require 'arel/algebra'
|
10
7
|
require 'arel/engines'
|
11
8
|
autoload :Session, 'arel/session'
|
12
9
|
|
13
|
-
VERSION = "0.
|
10
|
+
VERSION = "0.2.pre"
|
14
11
|
end
|
@@ -5,10 +5,13 @@ require 'arel/algebra/relations/utilities/externalization'
|
|
5
5
|
require 'arel/algebra/relations/row'
|
6
6
|
require 'arel/algebra/relations/writes'
|
7
7
|
require 'arel/algebra/relations/operations/alias'
|
8
|
+
require 'arel/algebra/relations/operations/from'
|
8
9
|
require 'arel/algebra/relations/operations/group'
|
10
|
+
require 'arel/algebra/relations/operations/having'
|
9
11
|
require 'arel/algebra/relations/operations/join'
|
10
12
|
require 'arel/algebra/relations/operations/order'
|
11
13
|
require 'arel/algebra/relations/operations/project'
|
12
14
|
require 'arel/algebra/relations/operations/where'
|
13
15
|
require 'arel/algebra/relations/operations/skip'
|
14
16
|
require 'arel/algebra/relations/operations/take'
|
17
|
+
require 'arel/algebra/relations/operations/lock'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Arel
|
2
|
+
class Having < Compound
|
3
|
+
attributes :relation, :havings
|
4
|
+
deriving :==
|
5
|
+
|
6
|
+
def initialize(relation, *havings, &block)
|
7
|
+
@relation = relation
|
8
|
+
@havings = (havings + arguments_from_block(relation, &block)) \
|
9
|
+
.collect { |g| g.bind(relation) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -43,7 +43,7 @@ module Arel
|
|
43
43
|
join(other_relation, OuterJoin)
|
44
44
|
end
|
45
45
|
|
46
|
-
[:where, :project, :order, :take, :skip, :group].each do |operation_name|
|
46
|
+
[:where, :project, :order, :take, :skip, :group, :from, :having].each do |operation_name|
|
47
47
|
class_eval <<-OPERATION, __FILE__, __LINE__
|
48
48
|
def #{operation_name}(*arguments, &block)
|
49
49
|
arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block)
|
@@ -51,6 +51,10 @@ module Arel
|
|
51
51
|
OPERATION
|
52
52
|
end
|
53
53
|
|
54
|
+
def lock(locking = nil)
|
55
|
+
Lock.new(self, locking)
|
56
|
+
end
|
57
|
+
|
54
58
|
def alias
|
55
59
|
Alias.new(self)
|
56
60
|
end
|
@@ -127,9 +131,12 @@ module Arel
|
|
127
131
|
def orders; [] end
|
128
132
|
def inserts; [] end
|
129
133
|
def groupings; [] end
|
134
|
+
def havings; [] end
|
130
135
|
def joins(formatter = nil); nil end # FIXME
|
131
136
|
def taken; nil end
|
132
137
|
def skipped; nil end
|
138
|
+
def sources; [] end
|
139
|
+
def locked; [] end
|
133
140
|
end
|
134
141
|
include DefaultOperations
|
135
142
|
end
|
@@ -2,10 +2,10 @@ module Arel
|
|
2
2
|
class Compound < Relation
|
3
3
|
attr_reader :relation
|
4
4
|
delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?,
|
5
|
-
:column_for, :engine,
|
5
|
+
:column_for, :engine, :sources, :locked, :table_alias,
|
6
6
|
:to => :relation
|
7
7
|
|
8
|
-
[:attributes, :wheres, :groupings, :orders].each do |operation_name|
|
8
|
+
[:attributes, :wheres, :groupings, :orders, :havings].each do |operation_name|
|
9
9
|
class_eval <<-OPERATION, __FILE__, __LINE__
|
10
10
|
def #{operation_name}
|
11
11
|
@#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) }
|
@@ -4,7 +4,8 @@ module Arel
|
|
4
4
|
def name_for(relation)
|
5
5
|
@used_names ||= Hash.new(0)
|
6
6
|
(@relation_names ||= Hash.new do |hash, relation|
|
7
|
-
|
7
|
+
name = relation.table_alias ? relation.table_alias : relation.name
|
8
|
+
@used_names[name] += 1
|
8
9
|
hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '')
|
9
10
|
end)[relation.table]
|
10
11
|
end
|
@@ -57,6 +57,12 @@ module Arel
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
class HavingClause < PassThrough
|
61
|
+
def attribute(attribute)
|
62
|
+
attribute
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
60
66
|
class WhereCondition < Formatter
|
61
67
|
def attribute(attribute)
|
62
68
|
"#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}"
|
@@ -12,11 +12,13 @@ module Arel
|
|
12
12
|
order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ')
|
13
13
|
|
14
14
|
query = build_query \
|
15
|
-
"SELECT #{select_clauses.to_s}",
|
16
|
-
"FROM #{
|
15
|
+
"SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}",
|
16
|
+
"FROM #{from_clauses}",
|
17
17
|
(joins(self) unless joins(self).blank? ),
|
18
|
-
("WHERE #{where_clauses.join("
|
19
|
-
("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? )
|
18
|
+
("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ),
|
19
|
+
("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
|
20
|
+
("HAVING #{having_clauses.join(', ')}" unless havings.blank? ),
|
21
|
+
("#{locked}" unless locked.blank? )
|
20
22
|
|
21
23
|
build_query \
|
22
24
|
"SELECT * FROM (#{query}) AS id_list",
|
@@ -27,13 +29,15 @@ module Arel
|
|
27
29
|
else
|
28
30
|
build_query \
|
29
31
|
"SELECT #{select_clauses.join(', ')}",
|
30
|
-
"FROM #{
|
32
|
+
"FROM #{from_clauses}",
|
31
33
|
(joins(self) unless joins(self).blank? ),
|
32
|
-
("WHERE #{where_clauses.join("
|
34
|
+
("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ),
|
33
35
|
("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
|
36
|
+
("HAVING #{having_clauses.join(', ')}" unless havings.blank? ),
|
34
37
|
("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ),
|
35
38
|
("LIMIT #{taken}" unless taken.blank? ),
|
36
|
-
("OFFSET #{skipped}" unless skipped.blank? )
|
39
|
+
("OFFSET #{skipped}" unless skipped.blank? ),
|
40
|
+
("#{locked}" unless engine.adapter_name =~ /SQLite/ || locked.blank?)
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
@@ -48,7 +52,11 @@ module Arel
|
|
48
52
|
protected
|
49
53
|
|
50
54
|
def build_query(*parts)
|
51
|
-
parts.compact.join("
|
55
|
+
parts.compact.join(" ")
|
56
|
+
end
|
57
|
+
|
58
|
+
def from_clauses
|
59
|
+
sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources
|
52
60
|
end
|
53
61
|
|
54
62
|
def select_clauses
|
@@ -63,6 +71,10 @@ module Arel
|
|
63
71
|
groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }
|
64
72
|
end
|
65
73
|
|
74
|
+
def having_clauses
|
75
|
+
havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) }
|
76
|
+
end
|
77
|
+
|
66
78
|
def order_clauses
|
67
79
|
orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }
|
68
80
|
end
|
@@ -3,10 +3,22 @@ module Arel
|
|
3
3
|
include Recursion::BaseCase
|
4
4
|
|
5
5
|
cattr_accessor :engine
|
6
|
-
attr_reader :name, :engine
|
6
|
+
attr_reader :name, :engine, :table_alias, :options
|
7
7
|
|
8
|
-
def initialize(name,
|
9
|
-
@name
|
8
|
+
def initialize(name, options = {})
|
9
|
+
@name = name.to_s
|
10
|
+
|
11
|
+
if options.is_a?(Hash)
|
12
|
+
@options = options
|
13
|
+
@engine = options[:engine] || Table.engine
|
14
|
+
@table_alias = options[:as].to_s if options[:as].present?
|
15
|
+
else
|
16
|
+
@engine = options # Table.new('foo', engine)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def as(table_alias)
|
21
|
+
Table.new(name, options.merge(:as => table_alias))
|
10
22
|
end
|
11
23
|
|
12
24
|
def attributes
|
@@ -4,7 +4,7 @@ module Arel
|
|
4
4
|
build_query \
|
5
5
|
"DELETE",
|
6
6
|
"FROM #{table_sql}",
|
7
|
-
("WHERE #{wheres.collect(&:to_sql).join('
|
7
|
+
("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ),
|
8
8
|
("LIMIT #{taken}" unless taken.blank? )
|
9
9
|
end
|
10
10
|
end
|
@@ -14,8 +14,19 @@ module Arel
|
|
14
14
|
insertion_attributes_values_sql = if record.is_a?(Value)
|
15
15
|
record.value
|
16
16
|
else
|
17
|
-
|
18
|
-
|
17
|
+
attributes = record.keys.sort_by do |attribute|
|
18
|
+
attribute.name.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
first = attributes.collect do |key|
|
22
|
+
engine.quote_column_name(key.name)
|
23
|
+
end.join(', ')
|
24
|
+
|
25
|
+
second = attributes.collect do |key|
|
26
|
+
key.format(record[key])
|
27
|
+
end.join(', ')
|
28
|
+
|
29
|
+
build_query "(#{first})", "VALUES (#{second})"
|
19
30
|
end
|
20
31
|
|
21
32
|
build_query \
|
@@ -37,9 +48,14 @@ module Arel
|
|
37
48
|
|
38
49
|
def assignment_sql
|
39
50
|
if assignments.respond_to?(:collect)
|
40
|
-
assignments.
|
51
|
+
attributes = assignments.keys.sort_by do |attribute|
|
52
|
+
attribute.name.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
attributes.map do |attribute|
|
56
|
+
value = assignments[attribute]
|
41
57
|
"#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}"
|
42
|
-
end.join("
|
58
|
+
end.join(", ")
|
43
59
|
else
|
44
60
|
assignments.value
|
45
61
|
end
|
@@ -47,7 +63,7 @@ module Arel
|
|
47
63
|
|
48
64
|
def build_update_conditions_sql
|
49
65
|
conditions = ""
|
50
|
-
conditions << " WHERE #{wheres.collect(&:to_sql).join('
|
66
|
+
conditions << " WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank?
|
51
67
|
conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank?
|
52
68
|
|
53
69
|
unless taken.blank?
|
@@ -4,8 +4,8 @@ module Arel
|
|
4
4
|
module Predicates
|
5
5
|
describe Equality do
|
6
6
|
before do
|
7
|
-
@relation1 = Table.new(:users)
|
8
|
-
@relation2 = Table.new(:photos)
|
7
|
+
@relation1 = Arel::Table.new(:users)
|
8
|
+
@relation2 = Arel::Table.new(:photos)
|
9
9
|
@attribute1 = @relation1[:id]
|
10
10
|
@attribute2 = @relation2[:user_id]
|
11
11
|
end
|
@@ -150,7 +150,7 @@ module Arel
|
|
150
150
|
describe '#delete' do
|
151
151
|
it 'manufactures a deletion relation' do
|
152
152
|
Session.start do
|
153
|
-
|
153
|
+
Session.new.should_receive(:delete).with(Deletion.new(@relation))
|
154
154
|
@relation.delete
|
155
155
|
end
|
156
156
|
end
|
@@ -160,7 +160,7 @@ module Arel
|
|
160
160
|
it 'manufactures an insertion relation' do
|
161
161
|
Session.start do
|
162
162
|
record = { @relation[:name] => 'carl' }
|
163
|
-
|
163
|
+
Session.new.should_receive(:create).with(Insert.new(@relation, record))
|
164
164
|
@relation.insert(record)
|
165
165
|
end
|
166
166
|
end
|
@@ -170,7 +170,7 @@ module Arel
|
|
170
170
|
it 'manufactures an update relation' do
|
171
171
|
Session.start do
|
172
172
|
assignments = { @relation[:name] => Value.new('bob', @relation) }
|
173
|
-
|
173
|
+
Session.new.should_receive(:update).with(Update.new(@relation, assignments))
|
174
174
|
@relation.update(assignments)
|
175
175
|
end
|
176
176
|
end
|
@@ -180,8 +180,8 @@ module Arel
|
|
180
180
|
|
181
181
|
describe Relation::Enumerable do
|
182
182
|
it "implements enumerable" do
|
183
|
-
|
184
|
-
@relation.
|
183
|
+
@relation.map { |value| value }.should ==
|
184
|
+
@relation.session.read(@relation).map { |value| value }
|
185
185
|
end
|
186
186
|
end
|
187
187
|
end
|
@@ -40,19 +40,19 @@ module Arel
|
|
40
40
|
|
41
41
|
describe '#create' do
|
42
42
|
it "executes an insertion on the connection" do
|
43
|
-
|
43
|
+
@insert.should_receive(:call)
|
44
44
|
@session.create(@insert)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
describe '#read' do
|
49
49
|
it "executes an selection on the connection" do
|
50
|
-
|
50
|
+
@read.should_receive(:call)
|
51
51
|
@session.read(@read)
|
52
52
|
end
|
53
53
|
|
54
54
|
it "is memoized" do
|
55
|
-
|
55
|
+
@read.should_receive(:call).once
|
56
56
|
@session.read(@read)
|
57
57
|
@session.read(@read)
|
58
58
|
end
|
@@ -60,14 +60,14 @@ module Arel
|
|
60
60
|
|
61
61
|
describe '#update' do
|
62
62
|
it "executes an update on the connection" do
|
63
|
-
|
63
|
+
@update.should_receive(:call)
|
64
64
|
@session.update(@update)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
68
|
describe '#delete' do
|
69
69
|
it "executes a delete on the connection" do
|
70
|
-
|
70
|
+
@delete.should_receive(:call)
|
71
71
|
@session.delete(@delete)
|
72
72
|
end
|
73
73
|
end
|
@@ -4,8 +4,8 @@ module Arel
|
|
4
4
|
module Predicates
|
5
5
|
describe Equality do
|
6
6
|
before do
|
7
|
-
@relation1 = Table.new(:users)
|
8
|
-
@relation2 = Table.new(:photos)
|
7
|
+
@relation1 = Arel::Table.new(:users)
|
8
|
+
@relation2 = Arel::Table.new(:photos)
|
9
9
|
@attribute1 = @relation1[:id]
|
10
10
|
@attribute2 = @relation2[:user_id]
|
11
11
|
end
|
@@ -4,11 +4,11 @@ module Arel
|
|
4
4
|
module Predicates
|
5
5
|
describe Predicate do
|
6
6
|
before do
|
7
|
-
@relation = Table.new(:users)
|
7
|
+
@relation = Arel::Table.new(:users)
|
8
8
|
@attribute1 = @relation[:id]
|
9
9
|
@attribute2 = @relation[:name]
|
10
|
-
@operand1 = Equality.new(@attribute1, 1)
|
11
|
-
@operand2 = Equality.new(@attribute2, "name")
|
10
|
+
@operand1 = Arel::Predicates::Equality.new(@attribute1, 1)
|
11
|
+
@operand2 = Arel::Predicates::Equality.new(@attribute2, "name")
|
12
12
|
end
|
13
13
|
|
14
14
|
describe "when being combined with another predicate with AND logic" do
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe Table do
|
5
|
+
before do
|
6
|
+
@relation = Table.new(:users)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#to_sql' do
|
10
|
+
it "manufactures a simple select query" do
|
11
|
+
sql = @relation.from("workers").to_sql
|
12
|
+
|
13
|
+
adapter_is :mysql do
|
14
|
+
sql.should be_like(%Q{
|
15
|
+
SELECT `users`.`id`, `users`.`name`
|
16
|
+
FROM workers
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
adapter_is_not :mysql do
|
21
|
+
sql.should be_like(%Q{
|
22
|
+
SELECT "users"."id", "users"."name"
|
23
|
+
FROM workers
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#to_sql' do
|
30
|
+
it "overrides and use last from clause given " do
|
31
|
+
sql = @relation.from("workers").from("users").to_sql
|
32
|
+
|
33
|
+
adapter_is :mysql do
|
34
|
+
sql.should be_like(%Q{
|
35
|
+
SELECT `users`.`id`, `users`.`name`
|
36
|
+
FROM users
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
adapter_is_not :mysql do
|
41
|
+
sql.should be_like(%Q{
|
42
|
+
SELECT "users"."id", "users"."name"
|
43
|
+
FROM users
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe Having do
|
5
|
+
before do
|
6
|
+
@relation = Table.new(:developers)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#to_sql' do
|
10
|
+
describe 'when given a predicate' do
|
11
|
+
it "manufactures sql with where clause conditions" do
|
12
|
+
sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000").to_sql
|
13
|
+
|
14
|
+
adapter_is :mysql do
|
15
|
+
sql.should be_like(%Q{
|
16
|
+
SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department`
|
17
|
+
FROM `developers`
|
18
|
+
GROUP BY `developers`.`department`
|
19
|
+
HAVING MIN(salary) > 1000
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
adapter_is_not :mysql do
|
24
|
+
sql.should be_like(%Q{
|
25
|
+
SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department"
|
26
|
+
FROM "developers"
|
27
|
+
GROUP BY "developers"."department"
|
28
|
+
HAVING MIN(salary) > 1000
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -5,13 +5,20 @@ module Arel
|
|
5
5
|
before do
|
6
6
|
@relation1 = Table.new(:users)
|
7
7
|
@relation2 = Table.new(:photos)
|
8
|
-
@
|
8
|
+
@predicate1 = @relation1[:id].eq(@relation2[:user_id])
|
9
|
+
|
10
|
+
@relation3 = Table.new(:users, :as => :super_users)
|
11
|
+
@relation4 = Table.new(:photos, :as => :super_photos)
|
12
|
+
|
13
|
+
@predicate2 = @relation3[:id].eq(@relation2[:user_id])
|
14
|
+
@predicate3 = @relation3[:id].eq(@relation4[:user_id])
|
9
15
|
end
|
10
16
|
|
11
17
|
describe '#to_sql' do
|
18
|
+
|
12
19
|
describe 'when joining with another relation' do
|
13
20
|
it 'manufactures sql joining the two tables on the predicate' do
|
14
|
-
sql = InnerJoin.new(@relation1, @relation2, @
|
21
|
+
sql = InnerJoin.new(@relation1, @relation2, @predicate1).to_sql
|
15
22
|
|
16
23
|
adapter_is :mysql do
|
17
24
|
sql.should be_like(%Q{
|
@@ -29,6 +36,51 @@ module Arel
|
|
29
36
|
})
|
30
37
|
end
|
31
38
|
end
|
39
|
+
|
40
|
+
describe 'when joining with another relation with an aliased table' do
|
41
|
+
it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do
|
42
|
+
sql = InnerJoin.new(@relation3, @relation2, @predicate2).to_sql
|
43
|
+
|
44
|
+
adapter_is :mysql do
|
45
|
+
sql.should be_like(%Q{
|
46
|
+
SELECT `super_users`.`id`, `super_users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`
|
47
|
+
FROM `users` AS `super_users`
|
48
|
+
INNER JOIN `photos` ON `super_users`.`id` = `photos`.`user_id`
|
49
|
+
})
|
50
|
+
end
|
51
|
+
|
52
|
+
adapter_is_not :mysql do
|
53
|
+
sql.should be_like(%Q{
|
54
|
+
SELECT "super_users"."id", "super_users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id"
|
55
|
+
FROM "users" AS "super_users"
|
56
|
+
INNER JOIN "photos" ON "super_users"."id" = "photos"."user_id"
|
57
|
+
})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'when joining with two relations with aliased tables' do
|
63
|
+
it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do
|
64
|
+
sql = InnerJoin.new(@relation3, @relation4, @predicate3).to_sql
|
65
|
+
|
66
|
+
adapter_is :mysql do
|
67
|
+
sql.should be_like(%Q{
|
68
|
+
SELECT `super_users`.`id`, `super_users`.`name`, `super_photos`.`id`, `super_photos`.`user_id`, `super_photos`.`camera_id`
|
69
|
+
FROM `users` AS `super_users`
|
70
|
+
INNER JOIN `photos` AS `super_photos` ON `super_users`.`id` = `super_photos`.`user_id`
|
71
|
+
})
|
72
|
+
end
|
73
|
+
|
74
|
+
adapter_is_not :mysql do
|
75
|
+
sql.should be_like(%Q{
|
76
|
+
SELECT "super_users"."id", "super_users"."name", "super_photos"."id", "super_photos"."user_id", "super_photos"."camera_id"
|
77
|
+
FROM "users" AS "super_users"
|
78
|
+
INNER JOIN "photos" AS "super_photos" ON "super_users"."id" = "super_photos"."user_id"
|
79
|
+
})
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
32
84
|
end
|
33
85
|
|
34
86
|
describe 'when joining with a string' do
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
describe Lock do
|
5
|
+
before do
|
6
|
+
@relation = Table.new(:users)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#to_sql' do
|
10
|
+
it "manufactures a simple select query lock" do
|
11
|
+
sql = @relation.lock.to_sql
|
12
|
+
|
13
|
+
adapter_is :mysql do
|
14
|
+
sql.should be_like(%Q{
|
15
|
+
SELECT `users`.`id`, `users`.`name`
|
16
|
+
FROM `users` FOR UPDATE
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
adapter_is :postgresql do
|
21
|
+
sql.should be_like(%Q{
|
22
|
+
SELECT "users"."id", "users"."name"
|
23
|
+
FROM "users" FOR UPDATE
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
adapter_is :sqlite3 do
|
28
|
+
sql.should be_like(%Q{
|
29
|
+
SELECT "users"."id", "users"."name"
|
30
|
+
FROM "users"
|
31
|
+
})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "manufactures a select query locking with a given lock" do
|
36
|
+
sql = @relation.lock("LOCK IN SHARE MODE").to_sql
|
37
|
+
|
38
|
+
adapter_is :mysql do
|
39
|
+
sql.should be_like(%Q{
|
40
|
+
SELECT `users`.`id`, `users`.`name`
|
41
|
+
FROM `users` LOCK IN SHARE MODE
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
adapter_is :postgresql do
|
46
|
+
sql.should be_like(%Q{
|
47
|
+
SELECT "users"."id", "users"."name"
|
48
|
+
FROM "users" LOCK IN SHARE MODE
|
49
|
+
})
|
50
|
+
end
|
51
|
+
|
52
|
+
adapter_is :sqlite3 do
|
53
|
+
sql.should be_like(%Q{
|
54
|
+
SELECT "users"."id", "users"."name"
|
55
|
+
FROM "users"
|
56
|
+
})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -26,6 +26,26 @@ module Arel
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
describe '#as' do
|
30
|
+
it "manufactures a simple select query using aliases" do
|
31
|
+
sql = @relation.as(:super_users).to_sql
|
32
|
+
|
33
|
+
adapter_is :mysql do
|
34
|
+
sql.should be_like(%Q{
|
35
|
+
SELECT `super_users`.`id`, `super_users`.`name`
|
36
|
+
FROM `users` AS `super_users`
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
adapter_is_not :mysql do
|
41
|
+
sql.should be_like(%Q{
|
42
|
+
SELECT "super_users"."id", "super_users"."name"
|
43
|
+
FROM "users" AS "super_users"
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
29
49
|
describe '#column_for' do
|
30
50
|
it "returns the column corresponding to the attribute" do
|
31
51
|
@relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' }
|
@@ -42,8 +62,8 @@ module Arel
|
|
42
62
|
|
43
63
|
describe '#reset' do
|
44
64
|
it "reloads columns from the database" do
|
45
|
-
lambda {
|
46
|
-
lambda { @relation.reset
|
65
|
+
lambda { @relation.engine.stub!(:columns => []) }.should_not change { @relation.attributes }
|
66
|
+
lambda { @relation.reset }.should change { @relation.attributes }
|
47
67
|
end
|
48
68
|
end
|
49
69
|
end
|
@@ -11,6 +11,13 @@ sql = <<-SQL
|
|
11
11
|
user_id INTEGER NOT NULL,
|
12
12
|
camera_id INTEGER NOT NULL
|
13
13
|
);
|
14
|
+
DROP TABLE IF EXISTS developers;
|
15
|
+
CREATE TABLE developers (
|
16
|
+
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
17
|
+
name VARCHAR(255) NOT NULL,
|
18
|
+
salary INTEGER NOT NULL,
|
19
|
+
department VARCHAR(255) NOT NULL
|
20
|
+
);
|
14
21
|
SQL
|
15
22
|
|
16
23
|
sql.split(/;/).select(&:present?).each do |sql_statement|
|
@@ -11,6 +11,13 @@ sql = <<-SQL
|
|
11
11
|
user_id INTEGER NOT NULL,
|
12
12
|
camera_id INTEGER NOT NULL
|
13
13
|
);
|
14
|
+
DROP TABLE IF EXISTS developers;
|
15
|
+
CREATE TABLE developers (
|
16
|
+
id SERIAL PRIMARY KEY NOT NULL,
|
17
|
+
name VARCHAR(255) NOT NULL,
|
18
|
+
salary INTEGER NOT NULL,
|
19
|
+
department VARCHAR(255) NOT NULL
|
20
|
+
);
|
14
21
|
SQL
|
15
22
|
|
16
23
|
sql.split(/;/).select(&:present?).each do |sql_statement|
|
@@ -11,6 +11,13 @@ sql = <<-SQL
|
|
11
11
|
user_id INTEGER NOT NULL,
|
12
12
|
camera_id INTEGER NOT NULL
|
13
13
|
);
|
14
|
+
DROP TABLE IF EXISTS developers;
|
15
|
+
CREATE TABLE developers (
|
16
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
17
|
+
name VARCHAR(255) NOT NULL,
|
18
|
+
salary INTEGER NOT NULL,
|
19
|
+
department VARCHAR(255) NOT NULL
|
20
|
+
);
|
14
21
|
SQL
|
15
22
|
|
16
23
|
sql.split(/;/).select(&:present?).each do |sql_statement|
|
data/spec/spec_helper.rb
CHANGED
@@ -48,7 +48,7 @@ Spec::Runner.configure do |config|
|
|
48
48
|
config.include BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher
|
49
49
|
config.include AdapterGuards
|
50
50
|
config.include Check
|
51
|
-
|
51
|
+
|
52
52
|
config.before do
|
53
53
|
Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base)
|
54
54
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Helmkamp
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2010-01-08 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -35,10 +35,12 @@ executables: []
|
|
35
35
|
extensions: []
|
36
36
|
|
37
37
|
extra_rdoc_files:
|
38
|
+
- History.txt
|
38
39
|
- README.markdown
|
39
40
|
files:
|
40
41
|
- .gitignore
|
41
42
|
- .gitmodules
|
43
|
+
- History.txt
|
42
44
|
- README.markdown
|
43
45
|
- Rakefile
|
44
46
|
- Thorfile
|
@@ -58,8 +60,11 @@ files:
|
|
58
60
|
- lib/arel/algebra/predicates.rb
|
59
61
|
- lib/arel/algebra/relations.rb
|
60
62
|
- lib/arel/algebra/relations/operations/alias.rb
|
63
|
+
- lib/arel/algebra/relations/operations/from.rb
|
61
64
|
- lib/arel/algebra/relations/operations/group.rb
|
65
|
+
- lib/arel/algebra/relations/operations/having.rb
|
62
66
|
- lib/arel/algebra/relations/operations/join.rb
|
67
|
+
- lib/arel/algebra/relations/operations/lock.rb
|
63
68
|
- lib/arel/algebra/relations/operations/order.rb
|
64
69
|
- lib/arel/algebra/relations/operations/project.rb
|
65
70
|
- lib/arel/algebra/relations/operations/skip.rb
|
@@ -147,9 +152,12 @@ files:
|
|
147
152
|
- spec/arel/engines/sql/unit/primitives/value_spec.rb
|
148
153
|
- spec/arel/engines/sql/unit/relations/alias_spec.rb
|
149
154
|
- spec/arel/engines/sql/unit/relations/delete_spec.rb
|
155
|
+
- spec/arel/engines/sql/unit/relations/from_spec.rb
|
150
156
|
- spec/arel/engines/sql/unit/relations/group_spec.rb
|
157
|
+
- spec/arel/engines/sql/unit/relations/having_spec.rb
|
151
158
|
- spec/arel/engines/sql/unit/relations/insert_spec.rb
|
152
159
|
- spec/arel/engines/sql/unit/relations/join_spec.rb
|
160
|
+
- spec/arel/engines/sql/unit/relations/lock_spec.rb
|
153
161
|
- spec/arel/engines/sql/unit/relations/order_spec.rb
|
154
162
|
- spec/arel/engines/sql/unit/relations/project_spec.rb
|
155
163
|
- spec/arel/engines/sql/unit/relations/skip_spec.rb
|
@@ -186,9 +194,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
186
194
|
version:
|
187
195
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
196
|
requirements:
|
189
|
-
- - "
|
197
|
+
- - ">"
|
190
198
|
- !ruby/object:Gem::Version
|
191
|
-
version:
|
199
|
+
version: 1.3.1
|
192
200
|
version:
|
193
201
|
requirements: []
|
194
202
|
|
@@ -241,9 +249,12 @@ test_files:
|
|
241
249
|
- spec/arel/engines/sql/unit/primitives/value_spec.rb
|
242
250
|
- spec/arel/engines/sql/unit/relations/alias_spec.rb
|
243
251
|
- spec/arel/engines/sql/unit/relations/delete_spec.rb
|
252
|
+
- spec/arel/engines/sql/unit/relations/from_spec.rb
|
244
253
|
- spec/arel/engines/sql/unit/relations/group_spec.rb
|
254
|
+
- spec/arel/engines/sql/unit/relations/having_spec.rb
|
245
255
|
- spec/arel/engines/sql/unit/relations/insert_spec.rb
|
246
256
|
- spec/arel/engines/sql/unit/relations/join_spec.rb
|
257
|
+
- spec/arel/engines/sql/unit/relations/lock_spec.rb
|
247
258
|
- spec/arel/engines/sql/unit/relations/order_spec.rb
|
248
259
|
- spec/arel/engines/sql/unit/relations/project_spec.rb
|
249
260
|
- spec/arel/engines/sql/unit/relations/skip_spec.rb
|