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.
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