arel-compat 0.4.0

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