activerecord 5.2.6 → 6.0.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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +609 -622
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations/association.rb +52 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +24 -28
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +5 -9
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +196 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +13 -26
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +189 -63
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +9 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +51 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +108 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -0,0 +1,257 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Predications
|
5
|
+
def not_eq(other)
|
6
|
+
Nodes::NotEqual.new self, quoted_node(other)
|
7
|
+
end
|
8
|
+
|
9
|
+
def not_eq_any(others)
|
10
|
+
grouping_any :not_eq, others
|
11
|
+
end
|
12
|
+
|
13
|
+
def not_eq_all(others)
|
14
|
+
grouping_all :not_eq, others
|
15
|
+
end
|
16
|
+
|
17
|
+
def eq(other)
|
18
|
+
Nodes::Equality.new self, quoted_node(other)
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_not_distinct_from(other)
|
22
|
+
Nodes::IsNotDistinctFrom.new self, quoted_node(other)
|
23
|
+
end
|
24
|
+
|
25
|
+
def is_distinct_from(other)
|
26
|
+
Nodes::IsDistinctFrom.new self, quoted_node(other)
|
27
|
+
end
|
28
|
+
|
29
|
+
def eq_any(others)
|
30
|
+
grouping_any :eq, others
|
31
|
+
end
|
32
|
+
|
33
|
+
def eq_all(others)
|
34
|
+
grouping_all :eq, quoted_array(others)
|
35
|
+
end
|
36
|
+
|
37
|
+
def between(other)
|
38
|
+
if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
|
39
|
+
self.in([])
|
40
|
+
elsif open_ended?(other.begin)
|
41
|
+
if other.end.nil? || open_ended?(other.end)
|
42
|
+
not_in([])
|
43
|
+
elsif other.exclude_end?
|
44
|
+
lt(other.end)
|
45
|
+
else
|
46
|
+
lteq(other.end)
|
47
|
+
end
|
48
|
+
elsif other.end.nil? || open_ended?(other.end)
|
49
|
+
gteq(other.begin)
|
50
|
+
elsif other.exclude_end?
|
51
|
+
gteq(other.begin).and(lt(other.end))
|
52
|
+
else
|
53
|
+
left = quoted_node(other.begin)
|
54
|
+
right = quoted_node(other.end)
|
55
|
+
Nodes::Between.new(self, left.and(right))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def in(other)
|
60
|
+
case other
|
61
|
+
when Arel::SelectManager
|
62
|
+
Arel::Nodes::In.new(self, other.ast)
|
63
|
+
when Range
|
64
|
+
if $VERBOSE
|
65
|
+
warn <<-eowarn
|
66
|
+
Passing a range to `#in` is deprecated. Call `#between`, instead.
|
67
|
+
eowarn
|
68
|
+
end
|
69
|
+
between(other)
|
70
|
+
when Enumerable
|
71
|
+
Nodes::In.new self, quoted_array(other)
|
72
|
+
else
|
73
|
+
Nodes::In.new self, quoted_node(other)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def in_any(others)
|
78
|
+
grouping_any :in, others
|
79
|
+
end
|
80
|
+
|
81
|
+
def in_all(others)
|
82
|
+
grouping_all :in, others
|
83
|
+
end
|
84
|
+
|
85
|
+
def not_between(other)
|
86
|
+
if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
|
87
|
+
not_in([])
|
88
|
+
elsif open_ended?(other.begin)
|
89
|
+
if other.end.nil? || open_ended?(other.end)
|
90
|
+
self.in([])
|
91
|
+
elsif other.exclude_end?
|
92
|
+
gteq(other.end)
|
93
|
+
else
|
94
|
+
gt(other.end)
|
95
|
+
end
|
96
|
+
elsif other.end.nil? || open_ended?(other.end)
|
97
|
+
lt(other.begin)
|
98
|
+
else
|
99
|
+
left = lt(other.begin)
|
100
|
+
right = if other.exclude_end?
|
101
|
+
gteq(other.end)
|
102
|
+
else
|
103
|
+
gt(other.end)
|
104
|
+
end
|
105
|
+
left.or(right)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def not_in(other)
|
110
|
+
case other
|
111
|
+
when Arel::SelectManager
|
112
|
+
Arel::Nodes::NotIn.new(self, other.ast)
|
113
|
+
when Range
|
114
|
+
if $VERBOSE
|
115
|
+
warn <<-eowarn
|
116
|
+
Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
|
117
|
+
eowarn
|
118
|
+
end
|
119
|
+
not_between(other)
|
120
|
+
when Enumerable
|
121
|
+
Nodes::NotIn.new self, quoted_array(other)
|
122
|
+
else
|
123
|
+
Nodes::NotIn.new self, quoted_node(other)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def not_in_any(others)
|
128
|
+
grouping_any :not_in, others
|
129
|
+
end
|
130
|
+
|
131
|
+
def not_in_all(others)
|
132
|
+
grouping_all :not_in, others
|
133
|
+
end
|
134
|
+
|
135
|
+
def matches(other, escape = nil, case_sensitive = false)
|
136
|
+
Nodes::Matches.new self, quoted_node(other), escape, case_sensitive
|
137
|
+
end
|
138
|
+
|
139
|
+
def matches_regexp(other, case_sensitive = true)
|
140
|
+
Nodes::Regexp.new self, quoted_node(other), case_sensitive
|
141
|
+
end
|
142
|
+
|
143
|
+
def matches_any(others, escape = nil, case_sensitive = false)
|
144
|
+
grouping_any :matches, others, escape, case_sensitive
|
145
|
+
end
|
146
|
+
|
147
|
+
def matches_all(others, escape = nil, case_sensitive = false)
|
148
|
+
grouping_all :matches, others, escape, case_sensitive
|
149
|
+
end
|
150
|
+
|
151
|
+
def does_not_match(other, escape = nil, case_sensitive = false)
|
152
|
+
Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive
|
153
|
+
end
|
154
|
+
|
155
|
+
def does_not_match_regexp(other, case_sensitive = true)
|
156
|
+
Nodes::NotRegexp.new self, quoted_node(other), case_sensitive
|
157
|
+
end
|
158
|
+
|
159
|
+
def does_not_match_any(others, escape = nil)
|
160
|
+
grouping_any :does_not_match, others, escape
|
161
|
+
end
|
162
|
+
|
163
|
+
def does_not_match_all(others, escape = nil)
|
164
|
+
grouping_all :does_not_match, others, escape
|
165
|
+
end
|
166
|
+
|
167
|
+
def gteq(right)
|
168
|
+
Nodes::GreaterThanOrEqual.new self, quoted_node(right)
|
169
|
+
end
|
170
|
+
|
171
|
+
def gteq_any(others)
|
172
|
+
grouping_any :gteq, others
|
173
|
+
end
|
174
|
+
|
175
|
+
def gteq_all(others)
|
176
|
+
grouping_all :gteq, others
|
177
|
+
end
|
178
|
+
|
179
|
+
def gt(right)
|
180
|
+
Nodes::GreaterThan.new self, quoted_node(right)
|
181
|
+
end
|
182
|
+
|
183
|
+
def gt_any(others)
|
184
|
+
grouping_any :gt, others
|
185
|
+
end
|
186
|
+
|
187
|
+
def gt_all(others)
|
188
|
+
grouping_all :gt, others
|
189
|
+
end
|
190
|
+
|
191
|
+
def lt(right)
|
192
|
+
Nodes::LessThan.new self, quoted_node(right)
|
193
|
+
end
|
194
|
+
|
195
|
+
def lt_any(others)
|
196
|
+
grouping_any :lt, others
|
197
|
+
end
|
198
|
+
|
199
|
+
def lt_all(others)
|
200
|
+
grouping_all :lt, others
|
201
|
+
end
|
202
|
+
|
203
|
+
def lteq(right)
|
204
|
+
Nodes::LessThanOrEqual.new self, quoted_node(right)
|
205
|
+
end
|
206
|
+
|
207
|
+
def lteq_any(others)
|
208
|
+
grouping_any :lteq, others
|
209
|
+
end
|
210
|
+
|
211
|
+
def lteq_all(others)
|
212
|
+
grouping_all :lteq, others
|
213
|
+
end
|
214
|
+
|
215
|
+
def when(right)
|
216
|
+
Nodes::Case.new(self).when quoted_node(right)
|
217
|
+
end
|
218
|
+
|
219
|
+
def concat(other)
|
220
|
+
Nodes::Concat.new self, other
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
def grouping_any(method_id, others, *extras)
|
226
|
+
nodes = others.map { |expr| send(method_id, expr, *extras) }
|
227
|
+
Nodes::Grouping.new nodes.inject { |memo, node|
|
228
|
+
Nodes::Or.new(memo, node)
|
229
|
+
}
|
230
|
+
end
|
231
|
+
|
232
|
+
def grouping_all(method_id, others, *extras)
|
233
|
+
nodes = others.map { |expr| send(method_id, expr, *extras) }
|
234
|
+
Nodes::Grouping.new Nodes::And.new(nodes)
|
235
|
+
end
|
236
|
+
|
237
|
+
def quoted_node(other)
|
238
|
+
Nodes.build_quoted(other, self)
|
239
|
+
end
|
240
|
+
|
241
|
+
def quoted_array(others)
|
242
|
+
others.map { |v| quoted_node(v) }
|
243
|
+
end
|
244
|
+
|
245
|
+
def infinity?(value)
|
246
|
+
value.respond_to?(:infinite?) && value.infinite?
|
247
|
+
end
|
248
|
+
|
249
|
+
def unboundable?(value)
|
250
|
+
value.respond_to?(:unboundable?) && value.unboundable?
|
251
|
+
end
|
252
|
+
|
253
|
+
def open_ended?(value)
|
254
|
+
infinity?(value) || unboundable?(value)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
class SelectManager < Arel::TreeManager
|
5
|
+
include Arel::Crud
|
6
|
+
|
7
|
+
STRING_OR_SYMBOL_CLASS = [Symbol, String]
|
8
|
+
|
9
|
+
def initialize(table = nil)
|
10
|
+
super()
|
11
|
+
@ast = Nodes::SelectStatement.new
|
12
|
+
@ctx = @ast.cores.last
|
13
|
+
from table
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize_copy(other)
|
17
|
+
super
|
18
|
+
@ctx = @ast.cores.last
|
19
|
+
end
|
20
|
+
|
21
|
+
def limit
|
22
|
+
@ast.limit && @ast.limit.expr
|
23
|
+
end
|
24
|
+
alias :taken :limit
|
25
|
+
|
26
|
+
def constraints
|
27
|
+
@ctx.wheres
|
28
|
+
end
|
29
|
+
|
30
|
+
def offset
|
31
|
+
@ast.offset && @ast.offset.expr
|
32
|
+
end
|
33
|
+
|
34
|
+
def skip(amount)
|
35
|
+
if amount
|
36
|
+
@ast.offset = Nodes::Offset.new(amount)
|
37
|
+
else
|
38
|
+
@ast.offset = nil
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
alias :offset= :skip
|
43
|
+
|
44
|
+
###
|
45
|
+
# Produces an Arel::Nodes::Exists node
|
46
|
+
def exists
|
47
|
+
Arel::Nodes::Exists.new @ast
|
48
|
+
end
|
49
|
+
|
50
|
+
def as(other)
|
51
|
+
create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other)
|
52
|
+
end
|
53
|
+
|
54
|
+
def lock(locking = Arel.sql("FOR UPDATE"))
|
55
|
+
case locking
|
56
|
+
when true
|
57
|
+
locking = Arel.sql("FOR UPDATE")
|
58
|
+
when Arel::Nodes::SqlLiteral
|
59
|
+
when String
|
60
|
+
locking = Arel.sql locking
|
61
|
+
end
|
62
|
+
|
63
|
+
@ast.lock = Nodes::Lock.new(locking)
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def locked
|
68
|
+
@ast.lock
|
69
|
+
end
|
70
|
+
|
71
|
+
def on(*exprs)
|
72
|
+
@ctx.source.right.last.right = Nodes::On.new(collapse(exprs))
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def group(*columns)
|
77
|
+
columns.each do |column|
|
78
|
+
# FIXME: backwards compat
|
79
|
+
column = Nodes::SqlLiteral.new(column) if String === column
|
80
|
+
column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column
|
81
|
+
|
82
|
+
@ctx.groups.push Nodes::Group.new column
|
83
|
+
end
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
def from(table)
|
88
|
+
table = Nodes::SqlLiteral.new(table) if String === table
|
89
|
+
|
90
|
+
case table
|
91
|
+
when Nodes::Join
|
92
|
+
@ctx.source.right << table
|
93
|
+
else
|
94
|
+
@ctx.source.left = table
|
95
|
+
end
|
96
|
+
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def froms
|
101
|
+
@ast.cores.map { |x| x.from }.compact
|
102
|
+
end
|
103
|
+
|
104
|
+
def join(relation, klass = Nodes::InnerJoin)
|
105
|
+
return self unless relation
|
106
|
+
|
107
|
+
case relation
|
108
|
+
when String, Nodes::SqlLiteral
|
109
|
+
raise EmptyJoinError if relation.empty?
|
110
|
+
klass = Nodes::StringJoin
|
111
|
+
end
|
112
|
+
|
113
|
+
@ctx.source.right << create_join(relation, nil, klass)
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def outer_join(relation)
|
118
|
+
join(relation, Nodes::OuterJoin)
|
119
|
+
end
|
120
|
+
|
121
|
+
def having(expr)
|
122
|
+
@ctx.havings << expr
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def window(name)
|
127
|
+
window = Nodes::NamedWindow.new(name)
|
128
|
+
@ctx.windows.push window
|
129
|
+
window
|
130
|
+
end
|
131
|
+
|
132
|
+
def project(*projections)
|
133
|
+
# FIXME: converting these to SQLLiterals is probably not good, but
|
134
|
+
# rails tests require it.
|
135
|
+
@ctx.projections.concat projections.map { |x|
|
136
|
+
STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x
|
137
|
+
}
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
def projections
|
142
|
+
@ctx.projections
|
143
|
+
end
|
144
|
+
|
145
|
+
def projections=(projections)
|
146
|
+
@ctx.projections = projections
|
147
|
+
end
|
148
|
+
|
149
|
+
def optimizer_hints(*hints)
|
150
|
+
unless hints.empty?
|
151
|
+
@ctx.optimizer_hints = Arel::Nodes::OptimizerHints.new(hints)
|
152
|
+
end
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
def distinct(value = true)
|
157
|
+
if value
|
158
|
+
@ctx.set_quantifier = Arel::Nodes::Distinct.new
|
159
|
+
else
|
160
|
+
@ctx.set_quantifier = nil
|
161
|
+
end
|
162
|
+
self
|
163
|
+
end
|
164
|
+
|
165
|
+
def distinct_on(value)
|
166
|
+
if value
|
167
|
+
@ctx.set_quantifier = Arel::Nodes::DistinctOn.new(value)
|
168
|
+
else
|
169
|
+
@ctx.set_quantifier = nil
|
170
|
+
end
|
171
|
+
self
|
172
|
+
end
|
173
|
+
|
174
|
+
def order(*expr)
|
175
|
+
# FIXME: We SHOULD NOT be converting these to SqlLiteral automatically
|
176
|
+
@ast.orders.concat expr.map { |x|
|
177
|
+
STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x
|
178
|
+
}
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
def orders
|
183
|
+
@ast.orders
|
184
|
+
end
|
185
|
+
|
186
|
+
def where_sql(engine = Table.engine)
|
187
|
+
return if @ctx.wheres.empty?
|
188
|
+
|
189
|
+
viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection)
|
190
|
+
Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value
|
191
|
+
end
|
192
|
+
|
193
|
+
def union(operation, other = nil)
|
194
|
+
if other
|
195
|
+
node_class = Nodes.const_get("Union#{operation.to_s.capitalize}")
|
196
|
+
else
|
197
|
+
other = operation
|
198
|
+
node_class = Nodes::Union
|
199
|
+
end
|
200
|
+
|
201
|
+
node_class.new self.ast, other.ast
|
202
|
+
end
|
203
|
+
|
204
|
+
def intersect(other)
|
205
|
+
Nodes::Intersect.new ast, other.ast
|
206
|
+
end
|
207
|
+
|
208
|
+
def except(other)
|
209
|
+
Nodes::Except.new ast, other.ast
|
210
|
+
end
|
211
|
+
alias :minus :except
|
212
|
+
|
213
|
+
def lateral(table_name = nil)
|
214
|
+
base = table_name.nil? ? ast : as(table_name)
|
215
|
+
Nodes::Lateral.new(base)
|
216
|
+
end
|
217
|
+
|
218
|
+
def with(*subqueries)
|
219
|
+
if subqueries.first.is_a? Symbol
|
220
|
+
node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}")
|
221
|
+
else
|
222
|
+
node_class = Nodes::With
|
223
|
+
end
|
224
|
+
@ast.with = node_class.new(subqueries.flatten)
|
225
|
+
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
def take(limit)
|
230
|
+
if limit
|
231
|
+
@ast.limit = Nodes::Limit.new(limit)
|
232
|
+
else
|
233
|
+
@ast.limit = nil
|
234
|
+
end
|
235
|
+
self
|
236
|
+
end
|
237
|
+
alias limit= take
|
238
|
+
|
239
|
+
def join_sources
|
240
|
+
@ctx.source.right
|
241
|
+
end
|
242
|
+
|
243
|
+
def source
|
244
|
+
@ctx.source
|
245
|
+
end
|
246
|
+
|
247
|
+
def comment(*values)
|
248
|
+
@ctx.comment = Nodes::Comment.new(values)
|
249
|
+
self
|
250
|
+
end
|
251
|
+
|
252
|
+
private
|
253
|
+
def collapse(exprs)
|
254
|
+
exprs = exprs.compact
|
255
|
+
exprs.map! { |expr|
|
256
|
+
if String === expr
|
257
|
+
# FIXME: Don't do this automatically
|
258
|
+
Arel.sql(expr)
|
259
|
+
else
|
260
|
+
expr
|
261
|
+
end
|
262
|
+
}
|
263
|
+
|
264
|
+
if exprs.length == 1
|
265
|
+
exprs.first
|
266
|
+
else
|
267
|
+
create_and exprs
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
data/lib/arel/table.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
class Table
|
5
|
+
include Arel::Crud
|
6
|
+
include Arel::FactoryMethods
|
7
|
+
|
8
|
+
@engine = nil
|
9
|
+
class << self; attr_accessor :engine; end
|
10
|
+
|
11
|
+
attr_accessor :name, :table_alias
|
12
|
+
|
13
|
+
# TableAlias and Table both have a #table_name which is the name of the underlying table
|
14
|
+
alias :table_name :name
|
15
|
+
|
16
|
+
def initialize(name, as: nil, type_caster: nil)
|
17
|
+
@name = name.to_s
|
18
|
+
@type_caster = type_caster
|
19
|
+
|
20
|
+
# Sometime AR sends an :as parameter to table, to let the table know
|
21
|
+
# that it is an Alias. We may want to override new, and return a
|
22
|
+
# TableAlias node?
|
23
|
+
if as.to_s == @name
|
24
|
+
as = nil
|
25
|
+
end
|
26
|
+
@table_alias = as
|
27
|
+
end
|
28
|
+
|
29
|
+
def alias(name = "#{self.name}_2")
|
30
|
+
Nodes::TableAlias.new(self, name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def from
|
34
|
+
SelectManager.new(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
def join(relation, klass = Nodes::InnerJoin)
|
38
|
+
return from unless relation
|
39
|
+
|
40
|
+
case relation
|
41
|
+
when String, Nodes::SqlLiteral
|
42
|
+
raise EmptyJoinError if relation.empty?
|
43
|
+
klass = Nodes::StringJoin
|
44
|
+
end
|
45
|
+
|
46
|
+
from.join(relation, klass)
|
47
|
+
end
|
48
|
+
|
49
|
+
def outer_join(relation)
|
50
|
+
join(relation, Nodes::OuterJoin)
|
51
|
+
end
|
52
|
+
|
53
|
+
def group(*columns)
|
54
|
+
from.group(*columns)
|
55
|
+
end
|
56
|
+
|
57
|
+
def order(*expr)
|
58
|
+
from.order(*expr)
|
59
|
+
end
|
60
|
+
|
61
|
+
def where(condition)
|
62
|
+
from.where condition
|
63
|
+
end
|
64
|
+
|
65
|
+
def project(*things)
|
66
|
+
from.project(*things)
|
67
|
+
end
|
68
|
+
|
69
|
+
def take(amount)
|
70
|
+
from.take amount
|
71
|
+
end
|
72
|
+
|
73
|
+
def skip(amount)
|
74
|
+
from.skip amount
|
75
|
+
end
|
76
|
+
|
77
|
+
def having(expr)
|
78
|
+
from.having expr
|
79
|
+
end
|
80
|
+
|
81
|
+
def [](name)
|
82
|
+
::Arel::Attribute.new self, name
|
83
|
+
end
|
84
|
+
|
85
|
+
def hash
|
86
|
+
# Perf note: aliases and table alias is excluded from the hash
|
87
|
+
# aliases can have a loop back to this table breaking hashes in parent
|
88
|
+
# relations, for the vast majority of cases @name is unique to a query
|
89
|
+
@name.hash
|
90
|
+
end
|
91
|
+
|
92
|
+
def eql?(other)
|
93
|
+
self.class == other.class &&
|
94
|
+
self.name == other.name &&
|
95
|
+
self.table_alias == other.table_alias
|
96
|
+
end
|
97
|
+
alias :== :eql?
|
98
|
+
|
99
|
+
def type_cast_for_database(attribute_name, value)
|
100
|
+
type_caster.type_cast_for_database(attribute_name, value)
|
101
|
+
end
|
102
|
+
|
103
|
+
def able_to_type_cast?
|
104
|
+
!type_caster.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
attr_reader :type_caster
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
class TreeManager
|
5
|
+
include Arel::FactoryMethods
|
6
|
+
|
7
|
+
module StatementMethods
|
8
|
+
def take(limit)
|
9
|
+
@ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def offset(offset)
|
14
|
+
@ast.offset = Nodes::Offset.new(Nodes.build_quoted(offset)) if offset
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def order(*expr)
|
19
|
+
@ast.orders = expr
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def key=(key)
|
24
|
+
@ast.key = Nodes.build_quoted(key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def key
|
28
|
+
@ast.key
|
29
|
+
end
|
30
|
+
|
31
|
+
def wheres=(exprs)
|
32
|
+
@ast.wheres = exprs
|
33
|
+
end
|
34
|
+
|
35
|
+
def where(expr)
|
36
|
+
@ast.wheres << expr
|
37
|
+
self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :ast
|
42
|
+
|
43
|
+
def initialize
|
44
|
+
@ctx = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_dot
|
48
|
+
collector = Arel::Collectors::PlainString.new
|
49
|
+
collector = Visitors::Dot.new.accept @ast, collector
|
50
|
+
collector.value
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_sql(engine = Table.engine)
|
54
|
+
collector = Arel::Collectors::SQLString.new
|
55
|
+
collector = engine.connection.visitor.accept @ast, collector
|
56
|
+
collector.value
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize_copy(other)
|
60
|
+
super
|
61
|
+
@ast = @ast.clone
|
62
|
+
end
|
63
|
+
|
64
|
+
def where(expr)
|
65
|
+
if Arel::TreeManager === expr
|
66
|
+
expr = expr.ast
|
67
|
+
end
|
68
|
+
@ctx.wheres << expr
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|