arel 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
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