arel-compat 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. data/History.txt +25 -0
  2. data/README.markdown +182 -0
  3. data/lib/arel.rb +13 -0
  4. data/lib/arel/algebra.rb +10 -0
  5. data/lib/arel/algebra/attributes.rb +7 -0
  6. data/lib/arel/algebra/attributes/attribute.rb +270 -0
  7. data/lib/arel/algebra/attributes/boolean.rb +21 -0
  8. data/lib/arel/algebra/attributes/decimal.rb +9 -0
  9. data/lib/arel/algebra/attributes/float.rb +9 -0
  10. data/lib/arel/algebra/attributes/integer.rb +10 -0
  11. data/lib/arel/algebra/attributes/string.rb +10 -0
  12. data/lib/arel/algebra/attributes/time.rb +6 -0
  13. data/lib/arel/algebra/core_extensions.rb +4 -0
  14. data/lib/arel/algebra/core_extensions/class.rb +32 -0
  15. data/lib/arel/algebra/core_extensions/hash.rb +11 -0
  16. data/lib/arel/algebra/core_extensions/object.rb +30 -0
  17. data/lib/arel/algebra/core_extensions/symbol.rb +9 -0
  18. data/lib/arel/algebra/expression.rb +43 -0
  19. data/lib/arel/algebra/header.rb +67 -0
  20. data/lib/arel/algebra/ordering.rb +23 -0
  21. data/lib/arel/algebra/predicates.rb +190 -0
  22. data/lib/arel/algebra/relations.rb +17 -0
  23. data/lib/arel/algebra/relations/operations/alias.rb +7 -0
  24. data/lib/arel/algebra/relations/operations/from.rb +6 -0
  25. data/lib/arel/algebra/relations/operations/group.rb +12 -0
  26. data/lib/arel/algebra/relations/operations/having.rb +17 -0
  27. data/lib/arel/algebra/relations/operations/join.rb +69 -0
  28. data/lib/arel/algebra/relations/operations/lock.rb +12 -0
  29. data/lib/arel/algebra/relations/operations/order.rb +19 -0
  30. data/lib/arel/algebra/relations/operations/project.rb +20 -0
  31. data/lib/arel/algebra/relations/operations/skip.rb +7 -0
  32. data/lib/arel/algebra/relations/operations/take.rb +11 -0
  33. data/lib/arel/algebra/relations/operations/where.rb +17 -0
  34. data/lib/arel/algebra/relations/relation.rb +136 -0
  35. data/lib/arel/algebra/relations/row.rb +26 -0
  36. data/lib/arel/algebra/relations/utilities/compound.rb +54 -0
  37. data/lib/arel/algebra/relations/utilities/externalization.rb +24 -0
  38. data/lib/arel/algebra/relations/utilities/nil.rb +7 -0
  39. data/lib/arel/algebra/relations/writes.rb +36 -0
  40. data/lib/arel/algebra/value.rb +14 -0
  41. data/lib/arel/engines.rb +2 -0
  42. data/lib/arel/engines/memory.rb +4 -0
  43. data/lib/arel/engines/memory/engine.rb +16 -0
  44. data/lib/arel/engines/memory/predicates.rb +99 -0
  45. data/lib/arel/engines/memory/primitives.rb +27 -0
  46. data/lib/arel/engines/memory/relations.rb +5 -0
  47. data/lib/arel/engines/memory/relations/array.rb +35 -0
  48. data/lib/arel/engines/memory/relations/compound.rb +9 -0
  49. data/lib/arel/engines/memory/relations/operations.rb +67 -0
  50. data/lib/arel/engines/memory/relations/writes.rb +7 -0
  51. data/lib/arel/engines/sql.rb +8 -0
  52. data/lib/arel/engines/sql/attributes.rb +40 -0
  53. data/lib/arel/engines/sql/christener.rb +14 -0
  54. data/lib/arel/engines/sql/compilers/ibm_db_compiler.rb +48 -0
  55. data/lib/arel/engines/sql/compilers/mysql_compiler.rb +11 -0
  56. data/lib/arel/engines/sql/compilers/oracle_compiler.rb +95 -0
  57. data/lib/arel/engines/sql/compilers/postgresql_compiler.rb +42 -0
  58. data/lib/arel/engines/sql/compilers/sqlite_compiler.rb +9 -0
  59. data/lib/arel/engines/sql/core_extensions.rb +4 -0
  60. data/lib/arel/engines/sql/core_extensions/array.rb +24 -0
  61. data/lib/arel/engines/sql/core_extensions/nil_class.rb +15 -0
  62. data/lib/arel/engines/sql/core_extensions/object.rb +19 -0
  63. data/lib/arel/engines/sql/core_extensions/range.rb +19 -0
  64. data/lib/arel/engines/sql/engine.rb +55 -0
  65. data/lib/arel/engines/sql/formatters.rb +122 -0
  66. data/lib/arel/engines/sql/predicates.rb +103 -0
  67. data/lib/arel/engines/sql/primitives.rb +97 -0
  68. data/lib/arel/engines/sql/relations.rb +10 -0
  69. data/lib/arel/engines/sql/relations/compiler.rb +118 -0
  70. data/lib/arel/engines/sql/relations/operations/alias.rb +5 -0
  71. data/lib/arel/engines/sql/relations/operations/join.rb +33 -0
  72. data/lib/arel/engines/sql/relations/relation.rb +65 -0
  73. data/lib/arel/engines/sql/relations/table.rb +88 -0
  74. data/lib/arel/engines/sql/relations/utilities/compound.rb +10 -0
  75. data/lib/arel/engines/sql/relations/utilities/externalization.rb +14 -0
  76. data/lib/arel/engines/sql/relations/utilities/nil.rb +6 -0
  77. data/lib/arel/engines/sql/relations/utilities/recursion.rb +13 -0
  78. data/lib/arel/engines/sql/relations/writes.rb +19 -0
  79. data/lib/arel/session.rb +51 -0
  80. data/lib/arel/version.rb +3 -0
  81. data/spec/algebra/unit/predicates/binary_spec.rb +35 -0
  82. data/spec/algebra/unit/predicates/equality_spec.rb +29 -0
  83. data/spec/algebra/unit/predicates/in_spec.rb +12 -0
  84. data/spec/algebra/unit/primitives/attribute_spec.rb +181 -0
  85. data/spec/algebra/unit/primitives/expression_spec.rb +45 -0
  86. data/spec/algebra/unit/primitives/value_spec.rb +15 -0
  87. data/spec/algebra/unit/relations/alias_spec.rb +16 -0
  88. data/spec/algebra/unit/relations/delete_spec.rb +9 -0
  89. data/spec/algebra/unit/relations/group_spec.rb +10 -0
  90. data/spec/algebra/unit/relations/insert_spec.rb +9 -0
  91. data/spec/algebra/unit/relations/join_spec.rb +25 -0
  92. data/spec/algebra/unit/relations/order_spec.rb +21 -0
  93. data/spec/algebra/unit/relations/project_spec.rb +34 -0
  94. data/spec/algebra/unit/relations/relation_spec.rb +187 -0
  95. data/spec/algebra/unit/relations/skip_spec.rb +10 -0
  96. data/spec/algebra/unit/relations/table_spec.rb +38 -0
  97. data/spec/algebra/unit/relations/take_spec.rb +10 -0
  98. data/spec/algebra/unit/relations/update_spec.rb +9 -0
  99. data/spec/algebra/unit/relations/where_spec.rb +19 -0
  100. data/spec/algebra/unit/session/session_spec.rb +84 -0
  101. data/spec/attributes/boolean_spec.rb +57 -0
  102. data/spec/attributes/float_spec.rb +119 -0
  103. data/spec/attributes/header_spec.rb +42 -0
  104. data/spec/attributes/integer_spec.rb +119 -0
  105. data/spec/attributes/string_spec.rb +43 -0
  106. data/spec/attributes/time_spec.rb +24 -0
  107. data/spec/engines/memory/integration/joins/cross_engine_spec.rb +51 -0
  108. data/spec/engines/memory/unit/relations/array_spec.rb +32 -0
  109. data/spec/engines/memory/unit/relations/insert_spec.rb +28 -0
  110. data/spec/engines/memory/unit/relations/join_spec.rb +31 -0
  111. data/spec/engines/memory/unit/relations/order_spec.rb +27 -0
  112. data/spec/engines/memory/unit/relations/project_spec.rb +27 -0
  113. data/spec/engines/memory/unit/relations/skip_spec.rb +26 -0
  114. data/spec/engines/memory/unit/relations/take_spec.rb +26 -0
  115. data/spec/engines/memory/unit/relations/where_spec.rb +39 -0
  116. data/spec/engines/sql/integration/joins/with_adjacency_spec.rb +258 -0
  117. data/spec/engines/sql/integration/joins/with_aggregations_spec.rb +221 -0
  118. data/spec/engines/sql/integration/joins/with_compounds_spec.rb +137 -0
  119. data/spec/engines/sql/unit/engine_spec.rb +45 -0
  120. data/spec/engines/sql/unit/predicates/binary_spec.rb +140 -0
  121. data/spec/engines/sql/unit/predicates/equality_spec.rb +75 -0
  122. data/spec/engines/sql/unit/predicates/in_spec.rb +179 -0
  123. data/spec/engines/sql/unit/predicates/noteq_spec.rb +75 -0
  124. data/spec/engines/sql/unit/predicates/predicates_spec.rb +79 -0
  125. data/spec/engines/sql/unit/primitives/attribute_spec.rb +36 -0
  126. data/spec/engines/sql/unit/primitives/expression_spec.rb +28 -0
  127. data/spec/engines/sql/unit/primitives/literal_spec.rb +43 -0
  128. data/spec/engines/sql/unit/primitives/value_spec.rb +29 -0
  129. data/spec/engines/sql/unit/relations/alias_spec.rb +53 -0
  130. data/spec/engines/sql/unit/relations/delete_spec.rb +83 -0
  131. data/spec/engines/sql/unit/relations/from_spec.rb +64 -0
  132. data/spec/engines/sql/unit/relations/group_spec.rb +72 -0
  133. data/spec/engines/sql/unit/relations/having_spec.rb +78 -0
  134. data/spec/engines/sql/unit/relations/insert_spec.rb +143 -0
  135. data/spec/engines/sql/unit/relations/join_spec.rb +180 -0
  136. data/spec/engines/sql/unit/relations/lock_spec.rb +86 -0
  137. data/spec/engines/sql/unit/relations/order_spec.rb +161 -0
  138. data/spec/engines/sql/unit/relations/project_spec.rb +143 -0
  139. data/spec/engines/sql/unit/relations/skip_spec.rb +41 -0
  140. data/spec/engines/sql/unit/relations/table_spec.rb +129 -0
  141. data/spec/engines/sql/unit/relations/take_spec.rb +49 -0
  142. data/spec/engines/sql/unit/relations/update_spec.rb +203 -0
  143. data/spec/engines/sql/unit/relations/where_spec.rb +72 -0
  144. data/spec/relations/join_spec.rb +42 -0
  145. data/spec/relations/relation_spec.rb +31 -0
  146. data/spec/shared/relation_spec.rb +255 -0
  147. data/spec/spec_helper.rb +36 -0
  148. data/spec/support/check.rb +6 -0
  149. data/spec/support/connections/mysql_connection.rb +14 -0
  150. data/spec/support/connections/oracle_connection.rb +17 -0
  151. data/spec/support/connections/postgresql_connection.rb +13 -0
  152. data/spec/support/connections/sqlite3_connection.rb +24 -0
  153. data/spec/support/guards.rb +28 -0
  154. data/spec/support/matchers.rb +4 -0
  155. data/spec/support/matchers/be_like.rb +24 -0
  156. data/spec/support/matchers/disambiguate_attributes.rb +28 -0
  157. data/spec/support/matchers/hash_the_same_as.rb +26 -0
  158. data/spec/support/matchers/have_rows.rb +18 -0
  159. data/spec/support/model.rb +62 -0
  160. data/spec/support/schemas/mysql_schema.rb +26 -0
  161. data/spec/support/schemas/oracle_schema.rb +20 -0
  162. data/spec/support/schemas/postgresql_schema.rb +26 -0
  163. data/spec/support/schemas/sqlite3_schema.rb +26 -0
  164. metadata +258 -0
@@ -0,0 +1,11 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class MySQLCompiler < GenericCompiler
4
+ def limited_update_conditions(conditions, taken)
5
+ conditions << " LIMIT #{taken}"
6
+ conditions
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,95 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class OracleCompiler < GenericCompiler
4
+
5
+ def select_sql
6
+ where_clauses_array = where_clauses
7
+ if limit_or_offset = !taken.blank? || !skipped.blank?
8
+ # if need to select first records without ORDER BY and GROUP BY
9
+ # then can use simple ROWNUM in WHERE clause
10
+ if skipped.blank? && groupings.blank? && orders.blank?
11
+ where_clauses_array << "ROWNUM <= #{taken}" if !taken.blank? && skipped.blank? && groupings.blank? && orders.blank?
12
+ limit_or_offset = false
13
+ end
14
+ end
15
+
16
+ # when limit or offset subquery is used then cannot use FOR UPDATE directly
17
+ # and need to construct separate subquery for primary key
18
+ if use_subquery_for_lock = limit_or_offset && !locked.blank?
19
+ quoted_primary_key = engine.quote_column_name(primary_key)
20
+ end
21
+ select_attributes_string = use_subquery_for_lock ? quoted_primary_key : select_clauses.join(', ')
22
+
23
+ # OracleEnhanced adapter workaround when ORDER BY is used with columns not
24
+ # present in DISTINCT columns list
25
+ order_clauses_array = if select_attributes_string =~ /DISTINCT.*FIRST_VALUE/ && !orders.blank?
26
+ order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?)
27
+ order = order.zip((0...order.size).to_a).map { |s,i| "alias_#{i}__ #{'DESC' if s =~ /\bdesc$/i}" }
28
+ else
29
+ order_clauses
30
+ end
31
+
32
+ query = build_query \
33
+ "SELECT #{select_attributes_string}",
34
+ "FROM #{from_clauses}",
35
+ (joins(self) unless joins(self).blank? ),
36
+ ("WHERE #{where_clauses_array.join(" AND ")}" unless where_clauses_array.blank? ),
37
+ ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
38
+ ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ),
39
+ ("ORDER BY #{order_clauses_array.join(', ')}" unless order_clauses_array.blank? )
40
+
41
+ # Use existing method from oracle_enhanced adapter to implement limit and offset using subqueries
42
+ engine.add_limit_offset!(query, :limit => taken, :offset => skipped) if limit_or_offset
43
+
44
+ if use_subquery_for_lock
45
+ build_query \
46
+ "SELECT #{select_clauses.join(', ')}",
47
+ "FROM #{from_clauses}",
48
+ "WHERE #{quoted_primary_key} IN (#{query})",
49
+ "#{locked}"
50
+ elsif !locked.blank?
51
+ build_query query, "#{locked}"
52
+ else
53
+ query
54
+ end
55
+ end
56
+
57
+ def delete_sql
58
+ where_clauses_array = wheres.collect(&:to_sql)
59
+ where_clauses_array << "ROWNUM <= #{taken}" unless taken.blank?
60
+ build_query \
61
+ "DELETE",
62
+ "FROM #{table_sql}",
63
+ ("WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? )
64
+ end
65
+
66
+ protected
67
+
68
+ def build_update_conditions_sql
69
+ conditions = ""
70
+ where_clauses_array = wheres.collect(&:to_sql)
71
+ # if need to select first records without ORDER BY
72
+ # then can use simple ROWNUM in WHERE clause
73
+ if !taken.blank? && orders.blank?
74
+ where_clauses_array << "ROWNUM <= #{taken}"
75
+ end
76
+ conditions << " WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank?
77
+ unless taken.blank?
78
+ conditions = limited_update_conditions(conditions, taken)
79
+ end
80
+ conditions
81
+ end
82
+
83
+ def limited_update_conditions(conditions, taken)
84
+ # need to add ORDER BY only if just taken ones should be updated
85
+ conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank?
86
+ quoted_primary_key = engine.quote_column_name(primary_key)
87
+ subquery = "SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions}"
88
+ # Use existing method from oracle_enhanced adapter to get taken records when ORDER BY is used
89
+ engine.add_limit_offset!(subquery, :limit => taken) unless orders.blank?
90
+ "WHERE #{quoted_primary_key} IN (#{subquery})"
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,42 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class PostgreSQLCompiler < GenericCompiler
4
+
5
+ def select_sql
6
+ if !orders.blank? && using_distinct_on?
7
+ subquery = build_query \
8
+ "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}",
9
+ "FROM #{from_clauses}",
10
+ (joins(self) unless joins(self).blank? ),
11
+ ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ),
12
+ ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ),
13
+ ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ),
14
+ ("#{locked}" unless locked.blank? )
15
+
16
+ build_query \
17
+ "SELECT * FROM (#{subquery}) AS id_list",
18
+ "ORDER BY #{aliased_orders(order_clauses)}",
19
+ ("LIMIT #{taken}" unless taken.blank? ),
20
+ ("OFFSET #{skipped}" unless skipped.blank? )
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def using_distinct_on?
27
+ select_clauses.any? { |x| x =~ /DISTINCT ON/ }
28
+ end
29
+
30
+ def aliased_orders(orders)
31
+ # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this
32
+ # by wrapping the +sql+ string as a sub-select and ordering in that query.
33
+ order = orders.join(', ').split(/,/).map { |s| s.strip }.reject(&:blank?)
34
+ order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ')
35
+ end
36
+
37
+ def supports_insert_with_returning?
38
+ engine.postgresql_version >= 80200
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class SQLiteCompiler < GenericCompiler
4
+ def locked
5
+ nil
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'arel/engines/sql/core_extensions/object'
2
+ require 'arel/engines/sql/core_extensions/array'
3
+ require 'arel/engines/sql/core_extensions/range'
4
+ require 'arel/engines/sql/core_extensions/nil_class'
@@ -0,0 +1,24 @@
1
+ module Arel
2
+ module Sql
3
+ module ArrayExtensions
4
+ def to_sql(formatter = nil)
5
+ if any?
6
+ "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")"
7
+ else
8
+ "(NULL)"
9
+ end
10
+ end
11
+
12
+ def inclusion_predicate_sql
13
+ "IN"
14
+ end
15
+
16
+ def exclusion_predicate_sql
17
+ "NOT IN"
18
+ end
19
+
20
+ Array.send(:include, self)
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,15 @@
1
+ module Arel
2
+ module Sql
3
+ module NilClassExtensions
4
+ def equality_predicate_sql
5
+ 'IS'
6
+ end
7
+
8
+ def inequality_predicate_sql
9
+ 'IS NOT'
10
+ end
11
+
12
+ NilClass.send(:include, self)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module Arel
2
+ module Sql
3
+ module ObjectExtensions
4
+ def to_sql(formatter)
5
+ formatter.scalar self
6
+ end
7
+
8
+ def equality_predicate_sql
9
+ '='
10
+ end
11
+
12
+ def inequality_predicate_sql
13
+ '!='
14
+ end
15
+
16
+ Object.send(:include, self)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Arel
2
+ module Sql
3
+ module RangeExtensions
4
+ def to_sql(formatter = nil)
5
+ formatter.range self.begin, self.end
6
+ end
7
+
8
+ def inclusion_predicate_sql
9
+ "BETWEEN"
10
+ end
11
+
12
+ def exclusion_predicate_sql
13
+ "NOT BETWEEN"
14
+ end
15
+
16
+ Range.send(:include, self)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ module Arel
2
+ module Sql
3
+ class Engine
4
+
5
+ def initialize(ar = nil)
6
+ @ar = ar
7
+ end
8
+
9
+ def connection
10
+ @ar ? @ar.connection : nil
11
+ end
12
+
13
+ def adapter_name
14
+ @adapter_name ||= case (name = connection.adapter_name)
15
+ # map OracleEnanced adapter to Oracle
16
+ when /Oracle/
17
+ 'Oracle'
18
+ else
19
+ name
20
+ end
21
+ end
22
+
23
+ def method_missing(method, *args, &block)
24
+ @ar.connection.send(method, *args, &block)
25
+ end
26
+
27
+ module CRUD
28
+ def create(relation)
29
+ primary_key_value = if relation.primary_key.blank?
30
+ nil
31
+ elsif relation.record.is_a?(Hash)
32
+ attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s }
33
+ attribute && attribute.last.value
34
+ end
35
+
36
+ connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value)
37
+ end
38
+
39
+ def read(relation)
40
+ rows = connection.select_rows(relation.to_sql)
41
+ Array.new(rows, relation.attributes)
42
+ end
43
+
44
+ def update(relation)
45
+ connection.update(relation.to_sql)
46
+ end
47
+
48
+ def delete(relation)
49
+ connection.delete(relation.to_sql)
50
+ end
51
+ end
52
+ include CRUD
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,122 @@
1
+ module Arel
2
+ module Sql
3
+ class Formatter
4
+ attr_reader :environment
5
+ delegate :christener, :engine, :to => :environment
6
+ delegate :name_for, :to => :christener
7
+ delegate :quote_table_name, :quote_column_name, :quote, :to => :engine
8
+
9
+ def initialize(environment)
10
+ @environment = environment
11
+ end
12
+ end
13
+
14
+ class SelectClause < Formatter
15
+ def attribute(attribute)
16
+ "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" +
17
+ (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "")
18
+ end
19
+
20
+ def expression(expression)
21
+ if expression.function_sql == "DISTINCT"
22
+ "#{expression.function_sql} #{expression.attribute.to_sql(self)}" +
23
+ (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '')
24
+ else
25
+ "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" +
26
+ (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id")
27
+ end
28
+ end
29
+
30
+ def select(select_sql, table)
31
+ "(#{select_sql}) AS #{quote_table_name(name_for(table))}"
32
+ end
33
+
34
+ def value(value)
35
+ value
36
+ end
37
+ end
38
+
39
+ class PassThrough < Formatter
40
+ def value(value)
41
+ value
42
+ end
43
+ end
44
+
45
+ class WhereClause < PassThrough
46
+ end
47
+
48
+ class OrderClause < PassThrough
49
+ def ordering(ordering)
50
+ "#{quote_table_name(name_for(ordering.attribute.original_relation))}.#{quote_column_name(ordering.attribute.name)} #{ordering.direction_sql}"
51
+ end
52
+ end
53
+
54
+ class GroupClause < PassThrough
55
+ def attribute(attribute)
56
+ "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}"
57
+ end
58
+ end
59
+
60
+ class HavingClause < PassThrough
61
+ def attribute(attribute)
62
+ attribute
63
+ end
64
+ end
65
+
66
+ class WhereCondition < Formatter
67
+ def attribute(attribute)
68
+ "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}"
69
+ end
70
+
71
+ def expression(expression)
72
+ "#{expression.function_sql}(#{expression.attribute.to_sql(self)})"
73
+ end
74
+
75
+ def value(value)
76
+ value.to_sql(self)
77
+ end
78
+
79
+ def scalar(value, column = nil)
80
+ quote(value, column)
81
+ end
82
+
83
+ def select(select_sql, table)
84
+ "(#{select_sql})"
85
+ end
86
+ end
87
+
88
+ class SelectStatement < Formatter
89
+ def select(select_sql, table)
90
+ select_sql
91
+ end
92
+ end
93
+
94
+ class TableReference < Formatter
95
+ def select(select_sql, table)
96
+ "(#{select_sql}) #{quote_table_name(name_for(table))}"
97
+ end
98
+
99
+ def table(table)
100
+ if table.name =~ /\s/
101
+ table.name
102
+ else
103
+ quote_table_name(table.name) +
104
+ (table.name != name_for(table) ? " #{quote_table_name(name_for(table))}" : '')
105
+ end
106
+ end
107
+ end
108
+
109
+ class Attribute < WhereCondition
110
+ def scalar(scalar)
111
+ quote(scalar, environment.column)
112
+ end
113
+
114
+ def range(left, right)
115
+ "#{scalar(left)} AND #{scalar(right)}"
116
+ end
117
+ end
118
+
119
+ class Value < WhereCondition
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,103 @@
1
+ module Arel
2
+ module Predicates
3
+ class Binary < Predicate
4
+ def to_sql(formatter = nil)
5
+ "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}"
6
+ end
7
+ end
8
+
9
+ class Unary < Predicate
10
+ def to_sql(formatter = nil)
11
+ "#{predicate_sql} (#{operand.to_sql(formatter)})"
12
+ end
13
+ end
14
+
15
+ class Not < Unary
16
+ def predicate_sql; "NOT" end
17
+ end
18
+
19
+ class CompoundPredicate < Binary
20
+ def to_sql(formatter = nil)
21
+ "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})"
22
+ end
23
+ end
24
+
25
+ class Or < CompoundPredicate
26
+ def predicate_sql; "OR" end
27
+ end
28
+
29
+ class And < CompoundPredicate
30
+ def predicate_sql; "AND" end
31
+ end
32
+
33
+ class Polyadic < Predicate
34
+ def to_sql(formatter = nil)
35
+ "(" +
36
+ predicates.map {|p| p.to_sql(formatter)}.join(" #{predicate_sql} ") +
37
+ ")"
38
+ end
39
+ end
40
+
41
+ class Any < Polyadic
42
+ def predicate_sql; "OR" end
43
+ end
44
+
45
+ class All < Polyadic
46
+ def predicate_sql; "AND" end
47
+ end
48
+
49
+ class Equality < Binary
50
+ def predicate_sql
51
+ operand2.equality_predicate_sql
52
+ end
53
+ end
54
+
55
+ class Inequality < Binary
56
+ def predicate_sql
57
+ operand2.inequality_predicate_sql
58
+ end
59
+ end
60
+
61
+ class GreaterThanOrEqualTo < Binary
62
+ def predicate_sql; '>=' end
63
+ end
64
+
65
+ class GreaterThan < Binary
66
+ def predicate_sql; '>' end
67
+ end
68
+
69
+ class LessThanOrEqualTo < Binary
70
+ def predicate_sql; '<=' end
71
+ end
72
+
73
+ class LessThan < Binary
74
+ def predicate_sql; '<' end
75
+ end
76
+
77
+ class Match < Binary
78
+ def predicate_sql; 'LIKE' end
79
+ end
80
+
81
+ class NotMatch < Binary
82
+ def predicate_sql; 'NOT LIKE' end
83
+ end
84
+
85
+ class In < Binary
86
+ def to_sql(formatter = nil)
87
+ if operand2.is_a?(Range) && operand2.exclude_end?
88
+ GreaterThanOrEqualTo.new(operand1, operand2.begin).and(
89
+ LessThan.new(operand1, operand2.end)
90
+ ).to_sql(formatter)
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ def predicate_sql; operand2.inclusion_predicate_sql end
97
+ end
98
+
99
+ class NotIn < Binary
100
+ def predicate_sql; operand2.exclusion_predicate_sql end
101
+ end
102
+ end
103
+ end