arel 2.0.1 → 2.0.2

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 (63) hide show
  1. data/.autotest +26 -0
  2. data/History.txt +18 -0
  3. data/Manifest.txt +31 -30
  4. data/README.markdown +7 -99
  5. data/Rakefile +3 -2
  6. data/arel.gemspec +18 -11
  7. data/lib/arel.rb +2 -1
  8. data/lib/arel/attributes/attribute.rb +1 -174
  9. data/lib/arel/crud.rb +2 -2
  10. data/lib/arel/delete_manager.rb +4 -4
  11. data/lib/arel/insert_manager.rb +8 -8
  12. data/lib/arel/nodes/exists.rb +2 -6
  13. data/lib/arel/nodes/sql_literal.rb +1 -0
  14. data/lib/arel/predications.rb +177 -0
  15. data/lib/arel/select_manager.rb +17 -11
  16. data/lib/arel/table.rb +4 -0
  17. data/lib/arel/tree_manager.rb +4 -3
  18. data/lib/arel/update_manager.rb +8 -8
  19. data/lib/arel/visitors.rb +4 -0
  20. data/lib/arel/visitors/dot.rb +3 -3
  21. data/lib/arel/visitors/join_sql.rb +2 -0
  22. data/lib/arel/visitors/mysql.rb +14 -0
  23. data/lib/arel/visitors/oracle.rb +31 -1
  24. data/lib/arel/visitors/order_clauses.rb +2 -0
  25. data/lib/arel/visitors/sqlite.rb +11 -0
  26. data/lib/arel/visitors/to_sql.rb +8 -11
  27. data/lib/arel/visitors/visitor.rb +19 -0
  28. data/{spec/attributes/attribute_spec.rb → test/attributes/test_attribute.rb} +84 -84
  29. data/test/helper.rb +13 -0
  30. data/{spec/nodes/count_spec.rb → test/nodes/test_count.rb} +3 -3
  31. data/{spec/nodes/delete_statement_spec.rb → test/nodes/test_delete_statement.rb} +3 -4
  32. data/{spec/nodes/equality_spec.rb → test/nodes/test_equality.rb} +10 -8
  33. data/{spec/nodes/insert_statement_spec.rb → test/nodes/test_insert_statement.rb} +6 -6
  34. data/{spec/nodes/or_spec.rb → test/nodes/test_or.rb} +6 -4
  35. data/test/nodes/test_select_core.rb +22 -0
  36. data/{spec/nodes/select_statement_spec.rb → test/nodes/test_select_statement.rb} +3 -4
  37. data/test/nodes/test_sql_literal.rb +52 -0
  38. data/{spec/nodes/sum_spec.rb → test/nodes/test_sum.rb} +2 -2
  39. data/{spec/nodes/update_statement_spec.rb → test/nodes/test_update_statement.rb} +6 -6
  40. data/{spec → test}/support/fake_record.rb +4 -2
  41. data/{spec/activerecord_compat_spec.rb → test/test_activerecord_compat.rb} +3 -3
  42. data/{spec/attributes_spec.rb → test/test_attributes.rb} +7 -7
  43. data/{spec/crud_spec.rb → test/test_crud.rb} +4 -4
  44. data/{spec/delete_manager_spec.rb → test/test_delete_manager.rb} +5 -16
  45. data/{spec/insert_manager_spec.rb → test/test_insert_manager.rb} +15 -31
  46. data/{spec/select_manager_spec.rb → test/test_select_manager.rb} +95 -77
  47. data/{spec/table_spec.rb → test/test_table.rb} +38 -32
  48. data/{spec/update_manager_spec.rb → test/test_update_manager.rb} +9 -21
  49. data/{spec/visitors/join_sql_spec.rb → test/visitors/test_join_sql.rb} +3 -3
  50. data/test/visitors/test_mysql.rb +27 -0
  51. data/{spec/visitors/oracle_spec.rb → test/visitors/test_oracle.rb} +26 -10
  52. data/{spec/visitors/postgres_spec.rb → test/visitors/test_postgres.rb} +2 -2
  53. data/test/visitors/test_sqlite.rb +18 -0
  54. data/{spec/visitors/to_sql_spec.rb → test/visitors/test_to_sql.rb} +25 -18
  55. metadata +101 -43
  56. data/spec/nodes/select_core_spec.rb +0 -21
  57. data/spec/nodes/sql_literal_spec.rb +0 -26
  58. data/spec/spec.opts +0 -3
  59. data/spec/spec_helper.rb +0 -18
  60. data/spec/support/check.rb +0 -6
  61. data/spec/support/matchers.rb +0 -4
  62. data/spec/support/matchers/be_like.rb +0 -24
  63. data/spec/support/shared/tree_manager_shared.rb +0 -9
data/lib/arel/crud.rb CHANGED
@@ -13,8 +13,8 @@ module Arel
13
13
  end
14
14
  um.table relation
15
15
  um.set values
16
- um.take @head.limit
17
- um.order(*@head.orders)
16
+ um.take @ast.limit
17
+ um.order(*@ast.orders)
18
18
  um.wheres = @ctx.wheres
19
19
 
20
20
  @engine.connection.update um.to_sql, 'AREL'
@@ -2,21 +2,21 @@ module Arel
2
2
  class DeleteManager < Arel::TreeManager
3
3
  def initialize engine
4
4
  super
5
- @head = Nodes::DeleteStatement.new
5
+ @ast = Nodes::DeleteStatement.new
6
6
  end
7
7
 
8
8
  def from relation
9
- @head.relation = relation
9
+ @ast.relation = relation
10
10
  self
11
11
  end
12
12
 
13
13
  def where expression
14
- @head.wheres << expression
14
+ @ast.wheres << expression
15
15
  self
16
16
  end
17
17
 
18
18
  def wheres= list
19
- @head.wheres = list
19
+ @ast.wheres = list
20
20
  end
21
21
  end
22
22
  end
@@ -2,32 +2,32 @@ module Arel
2
2
  class InsertManager < Arel::TreeManager
3
3
  def initialize engine
4
4
  super
5
- @head = Nodes::InsertStatement.new
5
+ @ast = Nodes::InsertStatement.new
6
6
  end
7
7
 
8
8
  def into table
9
- @head.relation = table
9
+ @ast.relation = table
10
10
  self
11
11
  end
12
12
 
13
- def columns; @head.columns end
14
- def values= val; @head.values = val; end
13
+ def columns; @ast.columns end
14
+ def values= val; @ast.values = val; end
15
15
 
16
16
  def insert fields
17
17
  return if fields.empty?
18
18
 
19
19
  if String === fields
20
- @head.values = SqlLiteral.new(fields)
20
+ @ast.values = SqlLiteral.new(fields)
21
21
  else
22
- @head.relation ||= fields.first.first.relation
22
+ @ast.relation ||= fields.first.first.relation
23
23
 
24
24
  values = []
25
25
 
26
26
  fields.each do |column, value|
27
- @head.columns << column
27
+ @ast.columns << column
28
28
  values << value
29
29
  end
30
- @head.values = Nodes::Values.new values, @head.columns
30
+ @ast.values = Nodes::Values.new values, @ast.columns
31
31
  end
32
32
  end
33
33
  end
@@ -1,11 +1,7 @@
1
1
  module Arel
2
2
  module Nodes
3
- class Exists
4
- attr_reader :select_stmt
5
-
6
- def initialize select_stmt
7
- @select_stmt = select_stmt
8
- end
3
+ class Exists < Arel::Nodes::Function
4
+ alias :select_stmt :expressions
9
5
  end
10
6
  end
11
7
  end
@@ -2,6 +2,7 @@ module Arel
2
2
  module Nodes
3
3
  class SqlLiteral < String
4
4
  include Arel::Expressions
5
+ include Arel::Predications
5
6
  end
6
7
  end
7
8
  end
@@ -0,0 +1,177 @@
1
+ module Arel
2
+ module Predications
3
+ def not_eq other
4
+ Nodes::NotEqual.new self, other
5
+ end
6
+
7
+ def not_eq_any others
8
+ grouping_any :not_eq, others
9
+ end
10
+
11
+ def not_eq_all others
12
+ grouping_all :not_eq, others
13
+ end
14
+
15
+ def eq other
16
+ Nodes::Equality.new self, other
17
+ end
18
+
19
+ def eq_any others
20
+ grouping_any :eq, others
21
+ end
22
+
23
+ def eq_all others
24
+ grouping_all :eq, others
25
+ end
26
+
27
+ def in other
28
+ case other
29
+ when Arel::SelectManager
30
+ Nodes::In.new self, other.to_a.map { |x| x.id }
31
+ when Range
32
+ if other.exclude_end?
33
+ left = Nodes::GreaterThanOrEqual.new(self, other.min)
34
+ right = Nodes::LessThan.new(self, other.max + 1)
35
+ Nodes::And.new left, right
36
+ else
37
+ Nodes::Between.new(self, Nodes::And.new(other.min, other.max))
38
+ end
39
+ else
40
+ Nodes::In.new self, other
41
+ end
42
+ end
43
+
44
+ def in_any others
45
+ grouping_any :in, others
46
+ end
47
+
48
+ def in_all others
49
+ grouping_all :in, others
50
+ end
51
+
52
+ def not_in other
53
+ case other
54
+ when Arel::SelectManager
55
+ Nodes::NotIn.new self, other.to_a.map { |x| x.id }
56
+ when Range
57
+ if other.exclude_end?
58
+ left = Nodes::LessThan.new(self, other.min)
59
+ right = Nodes::GreaterThanOrEqual.new(self, other.max)
60
+ Nodes::Or.new left, right
61
+ else
62
+ left = Nodes::LessThan.new(self, other.min)
63
+ right = Nodes::GreaterThan.new(self, other.max)
64
+ Nodes::Or.new left, right
65
+ end
66
+ else
67
+ Nodes::NotIn.new self, other
68
+ end
69
+ end
70
+
71
+ def not_in_any others
72
+ grouping_any :not_in, others
73
+ end
74
+
75
+ def not_in_all others
76
+ grouping_all :not_in, others
77
+ end
78
+
79
+ def matches other
80
+ Nodes::Matches.new self, other
81
+ end
82
+
83
+ def matches_any others
84
+ grouping_any :matches, others
85
+ end
86
+
87
+ def matches_all others
88
+ grouping_all :matches, others
89
+ end
90
+
91
+ def does_not_match other
92
+ Nodes::DoesNotMatch.new self, other
93
+ end
94
+
95
+ def does_not_match_any others
96
+ grouping_any :does_not_match, others
97
+ end
98
+
99
+ def does_not_match_all others
100
+ grouping_all :does_not_match, others
101
+ end
102
+
103
+ def gteq right
104
+ Nodes::GreaterThanOrEqual.new self, right
105
+ end
106
+
107
+ def gteq_any others
108
+ grouping_any :gteq, others
109
+ end
110
+
111
+ def gteq_all others
112
+ grouping_all :gteq, others
113
+ end
114
+
115
+ def gt right
116
+ Nodes::GreaterThan.new self, right
117
+ end
118
+
119
+ def gt_any others
120
+ grouping_any :gt, others
121
+ end
122
+
123
+ def gt_all others
124
+ grouping_all :gt, others
125
+ end
126
+
127
+ def lt right
128
+ Nodes::LessThan.new self, right
129
+ end
130
+
131
+ def lt_any others
132
+ grouping_any :lt, others
133
+ end
134
+
135
+ def lt_all others
136
+ grouping_all :lt, others
137
+ end
138
+
139
+ def lteq right
140
+ Nodes::LessThanOrEqual.new self, right
141
+ end
142
+
143
+ def lteq_any others
144
+ grouping_any :lteq, others
145
+ end
146
+
147
+ def lteq_all others
148
+ grouping_all :lteq, others
149
+ end
150
+
151
+ def asc
152
+ Nodes::Ordering.new self, :asc
153
+ end
154
+
155
+ def desc
156
+ Nodes::Ordering.new self, :desc
157
+ end
158
+
159
+ private
160
+
161
+ def grouping_any method_id, others
162
+ first = send method_id, others.shift
163
+
164
+ Nodes::Grouping.new others.inject(first) { |memo,expr|
165
+ Nodes::Or.new(memo, send(method_id, expr))
166
+ }
167
+ end
168
+
169
+ def grouping_all method_id, others
170
+ first = send method_id, others.shift
171
+
172
+ Nodes::Grouping.new others.inject(first) { |memo,expr|
173
+ Nodes::And.new(memo, send(method_id, expr))
174
+ }
175
+ end
176
+ end
177
+ end
@@ -4,13 +4,13 @@ module Arel
4
4
 
5
5
  def initialize engine, table = nil
6
6
  super(engine)
7
- @head = Nodes::SelectStatement.new
8
- @ctx = @head.cores.last
7
+ @ast = Nodes::SelectStatement.new
8
+ @ctx = @ast.cores.last
9
9
  from table
10
10
  end
11
11
 
12
12
  def taken
13
- @head.limit
13
+ @ast.limit
14
14
  end
15
15
 
16
16
  def constraints
@@ -18,10 +18,16 @@ module Arel
18
18
  end
19
19
 
20
20
  def skip amount
21
- @head.offset = Nodes::Offset.new(amount)
21
+ @ast.offset = Nodes::Offset.new(amount)
22
22
  self
23
23
  end
24
24
 
25
+ ###
26
+ # Produces an Arel::Nodes::Exists node
27
+ def exists
28
+ Arel::Nodes::Exists.new @ast
29
+ end
30
+
25
31
  def where_clauses
26
32
  #warn "where_clauses is deprecated" if $VERBOSE
27
33
  to_sql = Visitors::ToSql.new @engine
@@ -31,12 +37,12 @@ module Arel
31
37
  def lock locking = true
32
38
  # FIXME: do we even need to store this? If locking is +false+ shouldn't
33
39
  # we just remove the node from the AST?
34
- @head.lock = Nodes::Lock.new
40
+ @ast.lock = Nodes::Lock.new
35
41
  self
36
42
  end
37
43
 
38
44
  def locked
39
- @head.lock
45
+ @ast.lock
40
46
  end
41
47
 
42
48
  def on *exprs
@@ -96,7 +102,7 @@ module Arel
96
102
  # FIXME: converting these to SQLLiterals is probably not good, but
97
103
  # rails tests require it.
98
104
  @ctx.projections.concat projections.map { |x|
99
- String == x.class ? SqlLiteral.new(x) : x
105
+ [Symbol, String].include?(x.class) ? SqlLiteral.new(x.to_s) : x
100
106
  }
101
107
  self
102
108
  end
@@ -108,14 +114,14 @@ module Arel
108
114
 
109
115
  def order *expr
110
116
  # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically
111
- @head.orders.concat expr.map { |x|
117
+ @ast.orders.concat expr.map { |x|
112
118
  String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x
113
119
  }
114
120
  self
115
121
  end
116
122
 
117
123
  def orders
118
- @head.orders
124
+ @ast.orders
119
125
  end
120
126
 
121
127
  def wheres
@@ -130,7 +136,7 @@ module Arel
130
136
  end
131
137
 
132
138
  def take limit
133
- @head.limit = limit
139
+ @ast.limit = limit
134
140
  self
135
141
  end
136
142
 
@@ -142,7 +148,7 @@ module Arel
142
148
  end
143
149
 
144
150
  def order_clauses
145
- Visitors::OrderClauses.new(@engine).accept(@head).map { |x|
151
+ Visitors::OrderClauses.new(@engine).accept(@ast).map { |x|
146
152
  Nodes::SqlLiteral.new x
147
153
  }
148
154
  end
data/lib/arel/table.rb CHANGED
@@ -80,6 +80,10 @@ module Arel
80
80
  from(self).take amount
81
81
  end
82
82
 
83
+ def skip amount
84
+ from(self).skip amount
85
+ end
86
+
83
87
  def having expr
84
88
  from(self).having expr
85
89
  end
@@ -4,6 +4,7 @@ module Arel
4
4
  include Arel::Relation
5
5
 
6
6
  attr_accessor :visitor
7
+ attr_reader :ast, :engine
7
8
 
8
9
  def initialize engine
9
10
  @engine = engine
@@ -11,16 +12,16 @@ module Arel
11
12
  end
12
13
 
13
14
  def to_dot
14
- Visitors::Dot.new.accept @head
15
+ Visitors::Dot.new.accept @ast
15
16
  end
16
17
 
17
18
  def to_sql
18
- @visitor.accept @head
19
+ @visitor.accept @ast
19
20
  end
20
21
 
21
22
  def initialize_copy other
22
23
  super
23
- @head = @head.clone
24
+ @ast = @ast.clone
24
25
  end
25
26
  end
26
27
  end
@@ -2,40 +2,40 @@ module Arel
2
2
  class UpdateManager < Arel::TreeManager
3
3
  def initialize engine
4
4
  super
5
- @head = Nodes::UpdateStatement.new
5
+ @ast = Nodes::UpdateStatement.new
6
6
  end
7
7
 
8
8
  def take limit
9
- @head.limit = limit
9
+ @ast.limit = limit
10
10
  self
11
11
  end
12
12
 
13
13
  def order *expr
14
- @head.orders = expr
14
+ @ast.orders = expr
15
15
  self
16
16
  end
17
17
 
18
18
  ###
19
19
  # UPDATE +table+
20
20
  def table table
21
- @head.relation = table
21
+ @ast.relation = table
22
22
  self
23
23
  end
24
24
 
25
25
  def wheres= exprs
26
- @head.wheres = exprs
26
+ @ast.wheres = exprs
27
27
  end
28
28
 
29
29
  def where expr
30
- @head.wheres << expr
30
+ @ast.wheres << expr
31
31
  self
32
32
  end
33
33
 
34
34
  def set values
35
35
  if String === values
36
- @head.values = [values]
36
+ @ast.values = [values]
37
37
  else
38
- @head.values = values.map { |column,value|
38
+ @ast.values = values.map { |column,value|
39
39
  Nodes::Assignment.new(
40
40
  Nodes::UnqualifiedColumn.new(column),
41
41
  value