arel 0.1.2 → 0.2.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/History.txt +11 -0
  2. data/Rakefile +1 -1
  3. data/Thorfile +3 -1
  4. data/arel.gemspec +14 -3
  5. data/lib/arel.rb +1 -4
  6. data/lib/arel/algebra/relations.rb +3 -0
  7. data/lib/arel/algebra/relations/operations/from.rb +6 -0
  8. data/lib/arel/algebra/relations/operations/having.rb +13 -0
  9. data/lib/arel/algebra/relations/operations/lock.rb +12 -0
  10. data/lib/arel/algebra/relations/operations/project.rb +1 -1
  11. data/lib/arel/algebra/relations/relation.rb +8 -1
  12. data/lib/arel/algebra/relations/utilities/compound.rb +2 -2
  13. data/lib/arel/engines/memory/relations/operations.rb +6 -0
  14. data/lib/arel/engines/sql/christener.rb +2 -1
  15. data/lib/arel/engines/sql/formatters.rb +6 -0
  16. data/lib/arel/engines/sql/relations/relation.rb +20 -8
  17. data/lib/arel/engines/sql/relations/table.rb +15 -3
  18. data/lib/arel/engines/sql/relations/utilities/compound.rb +1 -1
  19. data/lib/arel/engines/sql/relations/writes.rb +22 -6
  20. data/spec/arel/algebra/unit/predicates/binary_spec.rb +1 -1
  21. data/spec/arel/algebra/unit/predicates/equality_spec.rb +2 -2
  22. data/spec/arel/algebra/unit/relations/relation_spec.rb +5 -5
  23. data/spec/arel/algebra/unit/session/session_spec.rb +5 -5
  24. data/spec/arel/engines/sql/unit/predicates/binary_spec.rb +1 -1
  25. data/spec/arel/engines/sql/unit/predicates/equality_spec.rb +2 -2
  26. data/spec/arel/engines/sql/unit/predicates/in_spec.rb +1 -1
  27. data/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +3 -3
  28. data/spec/arel/engines/sql/unit/relations/from_spec.rb +50 -0
  29. data/spec/arel/engines/sql/unit/relations/having_spec.rb +36 -0
  30. data/spec/arel/engines/sql/unit/relations/join_spec.rb +54 -2
  31. data/spec/arel/engines/sql/unit/relations/lock_spec.rb +61 -0
  32. data/spec/arel/engines/sql/unit/relations/table_spec.rb +22 -2
  33. data/spec/schemas/mysql_schema.rb +7 -0
  34. data/spec/schemas/postgresql_schema.rb +7 -0
  35. data/spec/schemas/sqlite3_schema.rb +7 -0
  36. data/spec/spec_helper.rb +1 -1
  37. metadata +15 -4
data/History.txt ADDED
@@ -0,0 +1,11 @@
1
+ == Git
2
+
3
+ * 1 major enhancement
4
+
5
+ * Ruby 1.9 compatibility
6
+
7
+ == 0.1.0 / 2009-08-06
8
+
9
+ * 1 major enhancement
10
+
11
+ * Birthday!
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 => ["check_dependencies", "spec:sqlite3", "spec:mysql", "spec:postgresql"]
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.1.2"
5
+ s.version = "0.2.pre"
6
6
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
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{2009-10-27}
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.1.2"
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,6 @@
1
+ module Arel
2
+ class From < Compound
3
+ attributes :relation, :sources
4
+ deriving :initialize, :==
5
+ end
6
+ end
@@ -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
+
@@ -0,0 +1,12 @@
1
+ module Arel
2
+ class Lock < Compound
3
+ attributes :relation, :locked
4
+ deriving :initialize, :==
5
+
6
+ def initialize(relation, locked, &block)
7
+ @relation = relation
8
+ @locked = locked.blank? ? " FOR UPDATE" : locked
9
+ end
10
+ end
11
+ end
12
+
@@ -14,7 +14,7 @@ module Arel
14
14
  end
15
15
 
16
16
  def externalizable?
17
- attributes.any?(&:aggregation?) or relation.externalizable?
17
+ attributes.any? { |a| a.respond_to?(:aggregation?) && a.aggregation? } || relation.externalizable?
18
18
  end
19
19
  end
20
20
  end
@@ -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) }
@@ -32,6 +32,12 @@ module Arel
32
32
  end
33
33
  end
34
34
 
35
+ class From < Compound
36
+ def eval
37
+ unoperated_rows[sources..-1]
38
+ end
39
+ end
40
+
35
41
  class Group < Compound
36
42
  def eval
37
43
  raise NotImplementedError
@@ -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
- @used_names[name = relation.name] += 1
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 #{table_sql(Sql::TableReference.new(self))}",
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("\n\tAND ")}" unless wheres.blank? ),
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 #{table_sql(Sql::TableReference.new(self))}",
32
+ "FROM #{from_clauses}",
31
33
  (joins(self) unless joins(self).blank? ),
32
- ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ),
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("\n")
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, engine = Table.engine)
9
- @name, @engine = name.to_s, engine
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
@@ -3,7 +3,7 @@ module Arel
3
3
  delegate :table, :table_sql, :to => :relation
4
4
 
5
5
  def build_query(*parts)
6
- parts.compact.join("\n")
6
+ parts.compact.join(" ")
7
7
  end
8
8
  end
9
9
  end
@@ -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('\n\tAND ')}" unless wheres.blank? ),
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
- build_query "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})",
18
- "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})"
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.collect do |attribute, value|
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(",\n")
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('\n\tAND ')}" unless wheres.blank?
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,7 +4,7 @@ module Arel
4
4
  module Predicates
5
5
  describe Binary 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
10
  class ConcreteBinary < Binary
@@ -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
- mock(Session.new).delete(Deletion.new(@relation))
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
- mock(Session.new).create(Insert.new(@relation, record))
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
- mock(Session.new).update(Update.new(@relation, assignments))
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
- check @relation.collect.should == @relation.session.read(@relation).collect
184
- @relation.first.should == @relation.session.read(@relation).first
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
- mock(@insert).call
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
- mock(@read).call
50
+ @read.should_receive(:call)
51
51
  @session.read(@read)
52
52
  end
53
53
 
54
54
  it "is memoized" do
55
- mock(@read).call.once
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
- mock(@update).call
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
- mock(@delete).call
70
+ @delete.should_receive(:call)
71
71
  @session.delete(@delete)
72
72
  end
73
73
  end
@@ -10,7 +10,7 @@ module Arel
10
10
  end
11
11
 
12
12
  before do
13
- @relation = Table.new(:users)
13
+ @relation = Arel::Table.new(:users)
14
14
  @attribute1 = @relation[:id]
15
15
  @attribute2 = @relation[:name]
16
16
  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,7 +4,7 @@ module Arel
4
4
  module Predicates
5
5
  describe In do
6
6
  before do
7
- @relation = Table.new(:users)
7
+ @relation = Arel::Table.new(:users)
8
8
  @attribute = @relation[:id]
9
9
  end
10
10
 
@@ -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
- @predicate = @relation1[:id].eq(@relation2[:user_id])
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, @predicate).to_sql
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 { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes }
46
- lambda { @relation.reset }.should change { @relation.attributes }
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
- config.mock_with :rr
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.1.2
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: 2009-10-27 00:00:00 -04:00
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: "0"
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