activerecord 7.0.8.7 → 7.2.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +781 -1777
- data/MIT-LICENSE +1 -1
- data/README.rdoc +30 -30
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +40 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +35 -21
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -3
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +153 -33
- data/lib/active_record/attributes.rb +96 -71
- data/lib/active_record/autosave_association.rb +81 -39
- data/lib/active_record/base.rb +11 -7
- data/lib/active_record/callbacks.rb +11 -25
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +343 -91
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +229 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +142 -12
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +539 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +289 -128
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +60 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +108 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +371 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +374 -203
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -45
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +51 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +298 -113
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +101 -105
- data/lib/active_record/core.rb +273 -178
- data/lib/active_record/counter_cache.rb +69 -35
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +56 -27
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +46 -22
- data/lib/active_record/encryption/encrypted_attribute_type.rb +48 -13
- data/lib/active_record/encryption/encryptor.rb +35 -19
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +130 -28
- data/lib/active_record/errors.rb +154 -34
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +48 -10
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +236 -118
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +96 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +35 -10
- data/lib/active_record/railtie.rb +131 -87
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +147 -155
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +270 -108
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +97 -21
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +3 -2
- data/lib/active_record/relation/query_methods.rb +585 -109
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +592 -92
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +90 -23
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +33 -11
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +23 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +108 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +114 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +56 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
|
@@ -63,7 +63,7 @@ module Arel # :nodoc: all
|
|
|
63
63
|
|
|
64
64
|
def visit_Arel_Nodes_Lateral(o, collector)
|
|
65
65
|
collector << "LATERAL "
|
|
66
|
-
grouping_parentheses o, collector
|
|
66
|
+
grouping_parentheses o.expr, collector
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
|
|
@@ -83,17 +83,6 @@ module Arel # :nodoc: all
|
|
|
83
83
|
|
|
84
84
|
def bind_block; BIND_BLOCK; end
|
|
85
85
|
|
|
86
|
-
# Used by Lateral visitor to enclose select queries in parentheses
|
|
87
|
-
def grouping_parentheses(o, collector)
|
|
88
|
-
if o.expr.is_a? Nodes::SelectStatement
|
|
89
|
-
collector << "("
|
|
90
|
-
visit o.expr, collector
|
|
91
|
-
collector << ")"
|
|
92
|
-
else
|
|
93
|
-
visit o.expr, collector
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
86
|
# Utilized by GroupingSet, Cube & RollUp visitors to
|
|
98
87
|
# handle grouping aggregation semantics
|
|
99
88
|
def grouping_array_or_grouping_element(o, collector)
|
data/lib/arel/visitors/sqlite.rb
CHANGED
|
@@ -33,6 +33,31 @@ module Arel # :nodoc: all
|
|
|
33
33
|
collector << " IS NOT "
|
|
34
34
|
visit o.right, collector
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
# Queries used in UNION should not be wrapped by parentheses,
|
|
38
|
+
# because it is an invalid syntax in SQLite.
|
|
39
|
+
def infix_value_with_paren(o, collector, value, suppress_parens = false)
|
|
40
|
+
collector << "( " unless suppress_parens
|
|
41
|
+
|
|
42
|
+
left = o.left.is_a?(Nodes::Grouping) ? o.left.expr : o.left
|
|
43
|
+
collector = if left.class == o.class
|
|
44
|
+
infix_value_with_paren(left, collector, value, true)
|
|
45
|
+
else
|
|
46
|
+
grouping_parentheses left, collector, false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
collector << value
|
|
50
|
+
|
|
51
|
+
right = o.right.is_a?(Nodes::Grouping) ? o.right.expr : o.right
|
|
52
|
+
collector = if right.class == o.class
|
|
53
|
+
infix_value_with_paren(right, collector, value, true)
|
|
54
|
+
else
|
|
55
|
+
grouping_parentheses right, collector, false
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
collector << " )" unless suppress_parens
|
|
59
|
+
collector
|
|
60
|
+
end
|
|
36
61
|
end
|
|
37
62
|
end
|
|
38
63
|
end
|
data/lib/arel/visitors/to_sql.rb
CHANGED
|
@@ -20,6 +20,7 @@ module Arel # :nodoc: all
|
|
|
20
20
|
|
|
21
21
|
private
|
|
22
22
|
def visit_Arel_Nodes_DeleteStatement(o, collector)
|
|
23
|
+
collector.retryable = false
|
|
23
24
|
o = prepare_delete_statement(o)
|
|
24
25
|
|
|
25
26
|
if has_join_sources?(o)
|
|
@@ -34,9 +35,11 @@ module Arel # :nodoc: all
|
|
|
34
35
|
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
|
35
36
|
collect_nodes_for o.orders, collector, " ORDER BY "
|
|
36
37
|
maybe_visit o.limit, collector
|
|
38
|
+
maybe_visit o.comment, collector
|
|
37
39
|
end
|
|
38
40
|
|
|
39
41
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
|
42
|
+
collector.retryable = false
|
|
40
43
|
o = prepare_update_statement(o)
|
|
41
44
|
|
|
42
45
|
collector << "UPDATE "
|
|
@@ -46,9 +49,11 @@ module Arel # :nodoc: all
|
|
|
46
49
|
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
|
47
50
|
collect_nodes_for o.orders, collector, " ORDER BY "
|
|
48
51
|
maybe_visit o.limit, collector
|
|
52
|
+
maybe_visit o.comment, collector
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
def visit_Arel_Nodes_InsertStatement(o, collector)
|
|
56
|
+
collector.retryable = false
|
|
52
57
|
collector << "INSERT INTO "
|
|
53
58
|
collector = visit o.relation, collector
|
|
54
59
|
|
|
@@ -333,7 +338,7 @@ module Arel # :nodoc: all
|
|
|
333
338
|
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
|
334
339
|
collector.preparable = false
|
|
335
340
|
|
|
336
|
-
|
|
341
|
+
visit o.left, collector
|
|
337
342
|
|
|
338
343
|
if o.type == :in
|
|
339
344
|
collector << " IN ("
|
|
@@ -350,7 +355,6 @@ module Arel # :nodoc: all
|
|
|
350
355
|
end
|
|
351
356
|
|
|
352
357
|
collector << ")"
|
|
353
|
-
collector
|
|
354
358
|
end
|
|
355
359
|
|
|
356
360
|
def visit_Arel_SelectManager(o, collector)
|
|
@@ -382,6 +386,7 @@ module Arel # :nodoc: all
|
|
|
382
386
|
end
|
|
383
387
|
|
|
384
388
|
def visit_Arel_Nodes_NamedFunction(o, collector)
|
|
389
|
+
collector.retryable = false
|
|
385
390
|
collector << o.name
|
|
386
391
|
collector << "("
|
|
387
392
|
collector << "DISTINCT " if o.distinct
|
|
@@ -569,18 +574,25 @@ module Arel # :nodoc: all
|
|
|
569
574
|
end
|
|
570
575
|
|
|
571
576
|
def visit_Arel_Table(o, collector)
|
|
572
|
-
if o.
|
|
573
|
-
|
|
577
|
+
if Arel::Nodes::Node === o.name
|
|
578
|
+
visit o.name, collector
|
|
574
579
|
else
|
|
575
580
|
collector << quote_table_name(o.name)
|
|
576
581
|
end
|
|
582
|
+
|
|
583
|
+
if o.table_alias
|
|
584
|
+
collector << " " << quote_table_name(o.table_alias)
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
collector
|
|
577
588
|
end
|
|
578
589
|
|
|
579
590
|
def visit_Arel_Nodes_In(o, collector)
|
|
580
|
-
collector.preparable = false
|
|
581
591
|
attr, values = o.left, o.right
|
|
582
592
|
|
|
583
593
|
if Array === values
|
|
594
|
+
collector.preparable = false
|
|
595
|
+
|
|
584
596
|
unless values.empty?
|
|
585
597
|
values.delete_if { |value| unboundable?(value) }
|
|
586
598
|
end
|
|
@@ -593,10 +605,11 @@ module Arel # :nodoc: all
|
|
|
593
605
|
end
|
|
594
606
|
|
|
595
607
|
def visit_Arel_Nodes_NotIn(o, collector)
|
|
596
|
-
collector.preparable = false
|
|
597
608
|
attr, values = o.left, o.right
|
|
598
609
|
|
|
599
610
|
if Array === values
|
|
611
|
+
collector.preparable = false
|
|
612
|
+
|
|
600
613
|
unless values.empty?
|
|
601
614
|
values.delete_if { |value| unboundable?(value) }
|
|
602
615
|
end
|
|
@@ -613,18 +626,7 @@ module Arel # :nodoc: all
|
|
|
613
626
|
end
|
|
614
627
|
|
|
615
628
|
def visit_Arel_Nodes_Or(o, collector)
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
while o = stack.pop
|
|
619
|
-
if o.is_a?(Arel::Nodes::Or)
|
|
620
|
-
stack.push o.right, o.left
|
|
621
|
-
else
|
|
622
|
-
visit o, collector
|
|
623
|
-
collector << " OR " unless stack.empty?
|
|
624
|
-
end
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
collector
|
|
629
|
+
inject_join o.children, collector, " OR "
|
|
628
630
|
end
|
|
629
631
|
|
|
630
632
|
def visit_Arel_Nodes_Assignment(o, collector)
|
|
@@ -729,6 +731,20 @@ module Arel # :nodoc: all
|
|
|
729
731
|
collector << quote_column_name(o.name)
|
|
730
732
|
end
|
|
731
733
|
|
|
734
|
+
def visit_Arel_Nodes_Cte(o, collector)
|
|
735
|
+
collector << quote_table_name(o.name)
|
|
736
|
+
collector << " AS "
|
|
737
|
+
|
|
738
|
+
case o.materialized
|
|
739
|
+
when true
|
|
740
|
+
collector << "MATERIALIZED "
|
|
741
|
+
when false
|
|
742
|
+
collector << "NOT MATERIALIZED "
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
visit o.relation, collector
|
|
746
|
+
end
|
|
747
|
+
|
|
732
748
|
def visit_Arel_Attributes_Attribute(o, collector)
|
|
733
749
|
join_name = o.relation.table_alias || o.relation.name
|
|
734
750
|
collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
|
|
@@ -749,9 +765,64 @@ module Arel # :nodoc: all
|
|
|
749
765
|
|
|
750
766
|
def visit_Arel_Nodes_SqlLiteral(o, collector)
|
|
751
767
|
collector.preparable = false
|
|
768
|
+
collector.retryable &&= o.retryable
|
|
752
769
|
collector << o.to_s
|
|
753
770
|
end
|
|
754
771
|
|
|
772
|
+
def visit_Arel_Nodes_BoundSqlLiteral(o, collector)
|
|
773
|
+
collector.retryable = false
|
|
774
|
+
bind_index = 0
|
|
775
|
+
|
|
776
|
+
new_bind = lambda do |value|
|
|
777
|
+
if Arel.arel_node?(value)
|
|
778
|
+
visit value, collector
|
|
779
|
+
elsif value.is_a?(Array)
|
|
780
|
+
if value.empty?
|
|
781
|
+
collector << @connection.quote(nil)
|
|
782
|
+
else
|
|
783
|
+
if value.none? { |v| Arel.arel_node?(v) }
|
|
784
|
+
collector.add_binds(value.map { |v| @connection.cast_bound_value(v) }, &bind_block)
|
|
785
|
+
else
|
|
786
|
+
value.each_with_index do |v, i|
|
|
787
|
+
collector << ", " unless i == 0
|
|
788
|
+
if Arel.arel_node?(v)
|
|
789
|
+
visit v, collector
|
|
790
|
+
else
|
|
791
|
+
collector.add_bind(@connection.cast_bound_value(v), &bind_block)
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
end
|
|
795
|
+
end
|
|
796
|
+
else
|
|
797
|
+
collector.add_bind(@connection.cast_bound_value(value), &bind_block)
|
|
798
|
+
end
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
if o.positional_binds
|
|
802
|
+
o.sql_with_placeholders.scan(/\?|([^?]+)/) do
|
|
803
|
+
if $1
|
|
804
|
+
collector << $1
|
|
805
|
+
else
|
|
806
|
+
value = o.positional_binds[bind_index]
|
|
807
|
+
bind_index += 1
|
|
808
|
+
|
|
809
|
+
new_bind.call(value)
|
|
810
|
+
end
|
|
811
|
+
end
|
|
812
|
+
else
|
|
813
|
+
o.sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)|([^:]+|.)/) do
|
|
814
|
+
if $2
|
|
815
|
+
collector << $2
|
|
816
|
+
else
|
|
817
|
+
value = o.named_binds[$1.to_sym]
|
|
818
|
+
new_bind.call(value)
|
|
819
|
+
end
|
|
820
|
+
end
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
collector
|
|
824
|
+
end
|
|
825
|
+
|
|
755
826
|
def visit_Integer(o, collector)
|
|
756
827
|
collector << o.to_s
|
|
757
828
|
end
|
|
@@ -791,6 +862,10 @@ module Arel # :nodoc: all
|
|
|
791
862
|
end
|
|
792
863
|
alias :visit_Set :visit_Array
|
|
793
864
|
|
|
865
|
+
def visit_Arel_Nodes_Fragments(o, collector)
|
|
866
|
+
inject_join o.values, collector, " "
|
|
867
|
+
end
|
|
868
|
+
|
|
794
869
|
def quote(value)
|
|
795
870
|
return value if Arel::Nodes::SqlLiteral === value
|
|
796
871
|
@connection.quote value
|
|
@@ -854,7 +929,8 @@ module Arel # :nodoc: all
|
|
|
854
929
|
stmt.limit = nil
|
|
855
930
|
stmt.offset = nil
|
|
856
931
|
stmt.orders = []
|
|
857
|
-
|
|
932
|
+
columns = Arel::Nodes::Grouping.new(o.key)
|
|
933
|
+
stmt.wheres = [Nodes::In.new(columns, [build_subselect(o.key, o)])]
|
|
858
934
|
stmt.relation = o.relation.left if has_join_sources?(o)
|
|
859
935
|
stmt.groups = o.groups unless o.groups.empty?
|
|
860
936
|
stmt.havings = o.havings unless o.havings.empty?
|
|
@@ -891,18 +967,34 @@ module Arel # :nodoc: all
|
|
|
891
967
|
collector = if o.left.class == o.class
|
|
892
968
|
infix_value_with_paren(o.left, collector, value, true)
|
|
893
969
|
else
|
|
894
|
-
|
|
970
|
+
grouping_parentheses o.left, collector, false
|
|
895
971
|
end
|
|
896
972
|
collector << value
|
|
897
973
|
collector = if o.right.class == o.class
|
|
898
974
|
infix_value_with_paren(o.right, collector, value, true)
|
|
899
975
|
else
|
|
900
|
-
|
|
976
|
+
grouping_parentheses o.right, collector, false
|
|
901
977
|
end
|
|
902
978
|
collector << " )" unless suppress_parens
|
|
903
979
|
collector
|
|
904
980
|
end
|
|
905
981
|
|
|
982
|
+
# Used by some visitors to enclose select queries in parentheses
|
|
983
|
+
def grouping_parentheses(o, collector, always_wrap_selects = true)
|
|
984
|
+
if o.is_a?(Nodes::SelectStatement) && (always_wrap_selects || require_parentheses?(o))
|
|
985
|
+
collector << "("
|
|
986
|
+
visit o, collector
|
|
987
|
+
collector << ")"
|
|
988
|
+
collector
|
|
989
|
+
else
|
|
990
|
+
visit o, collector
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
def require_parentheses?(o)
|
|
995
|
+
!o.orders.empty? || o.limit || o.offset
|
|
996
|
+
end
|
|
997
|
+
|
|
906
998
|
def aggregate(name, o, collector)
|
|
907
999
|
collector << "#{name}("
|
|
908
1000
|
if o.distinct
|
|
@@ -933,19 +1025,7 @@ module Arel # :nodoc: all
|
|
|
933
1025
|
def collect_ctes(children, collector)
|
|
934
1026
|
children.each_with_index do |child, i|
|
|
935
1027
|
collector << ", " unless i == 0
|
|
936
|
-
|
|
937
|
-
case child
|
|
938
|
-
when Arel::Nodes::As
|
|
939
|
-
name = child.left.name
|
|
940
|
-
relation = child.right
|
|
941
|
-
when Arel::Nodes::TableAlias
|
|
942
|
-
name = child.name
|
|
943
|
-
relation = child.relation
|
|
944
|
-
end
|
|
945
|
-
|
|
946
|
-
collector << quote_table_name(name)
|
|
947
|
-
collector << " AS "
|
|
948
|
-
visit relation, collector
|
|
1028
|
+
visit child.to_cte, collector
|
|
949
1029
|
end
|
|
950
1030
|
|
|
951
1031
|
collector
|
|
@@ -16,8 +16,8 @@ module Arel # :nodoc: all
|
|
|
16
16
|
|
|
17
17
|
def self.dispatch_cache
|
|
18
18
|
@dispatch_cache ||= Hash.new do |hash, klass|
|
|
19
|
-
hash[klass] = "visit_#{(klass.name ||
|
|
20
|
-
end
|
|
19
|
+
hash[klass] = :"visit_#{(klass.name || "").gsub("::", "_")}"
|
|
20
|
+
end.compare_by_identity
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def get_dispatch_cache
|
data/lib/arel.rb
CHANGED
|
@@ -35,12 +35,30 @@ module Arel
|
|
|
35
35
|
# Great caution should be taken to avoid SQL injection vulnerabilities.
|
|
36
36
|
# This method should not be used with unsafe values such as request
|
|
37
37
|
# parameters or model attributes.
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
#
|
|
39
|
+
# Take a look at the {security guide}[https://guides.rubyonrails.org/security.html#sql-injection]
|
|
40
|
+
# for more information.
|
|
41
|
+
#
|
|
42
|
+
# To construct a more complex query fragment, including the possible
|
|
43
|
+
# use of user-provided values, the +sql_string+ may contain <tt>?</tt> and
|
|
44
|
+
# +:key+ placeholders, corresponding to the additional arguments. Note
|
|
45
|
+
# that this behavior only applies when bind value parameters are
|
|
46
|
+
# supplied in the call; without them, the placeholder tokens have no
|
|
47
|
+
# special meaning, and will be passed through to the query as-is.
|
|
48
|
+
#
|
|
49
|
+
# The +:retryable+ option can be used to mark the SQL as safe to retry.
|
|
50
|
+
# Use this option only if the SQL is idempotent, as it could be executed
|
|
51
|
+
# more than once.
|
|
52
|
+
def self.sql(sql_string, *positional_binds, retryable: false, **named_binds)
|
|
53
|
+
if positional_binds.empty? && named_binds.empty?
|
|
54
|
+
Arel::Nodes::SqlLiteral.new(sql_string, retryable: retryable)
|
|
55
|
+
else
|
|
56
|
+
Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
|
|
57
|
+
end
|
|
40
58
|
end
|
|
41
59
|
|
|
42
60
|
def self.star # :nodoc:
|
|
43
|
-
sql
|
|
61
|
+
sql("*", retryable: true)
|
|
44
62
|
end
|
|
45
63
|
|
|
46
64
|
def self.arel_node?(value) # :nodoc:
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generates an `ApplicationRecord` base class for other models to inherit from.
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
`bin/rails generate application_record`
|
|
6
|
+
|
|
7
|
+
This generates the base class. A test is not generated because no
|
|
8
|
+
behaviour is included in `ApplicationRecord` by default.
|
|
@@ -12,7 +12,10 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
|
12
12
|
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
|
13
13
|
<% end -%>
|
|
14
14
|
<% end -%>
|
|
15
|
-
<%
|
|
15
|
+
<% unless attributes.empty? -%>
|
|
16
|
+
|
|
17
|
+
<% end -%>
|
|
18
|
+
<% if options[:timestamps] -%>
|
|
16
19
|
t.timestamps
|
|
17
20
|
<% end -%>
|
|
18
21
|
end
|
|
@@ -41,11 +41,13 @@ module ActiveRecord
|
|
|
41
41
|
|
|
42
42
|
def configured_migrate_path
|
|
43
43
|
return unless database = options[:database]
|
|
44
|
+
|
|
44
45
|
config = ActiveRecord::Base.configurations.configs_for(
|
|
45
46
|
env_name: Rails.env,
|
|
46
47
|
name: database
|
|
47
48
|
)
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
Array(config&.migrations_paths).first
|
|
49
51
|
end
|
|
50
52
|
end
|
|
51
53
|
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generates a new model. Pass the model name, either CamelCased or
|
|
3
|
+
under_scored, and an optional list of attribute pairs as arguments.
|
|
4
|
+
|
|
5
|
+
Attribute pairs are field:type arguments specifying the
|
|
6
|
+
model's attributes. Timestamps are added by default, so you don't have to
|
|
7
|
+
specify them by hand as 'created_at:datetime updated_at:datetime'.
|
|
8
|
+
|
|
9
|
+
As a special case, specifying 'password:digest' will generate a
|
|
10
|
+
password_digest field of string type, and configure your generated model and
|
|
11
|
+
tests for use with Active Model has_secure_password (assuming the default ORM
|
|
12
|
+
and test framework are being used).
|
|
13
|
+
|
|
14
|
+
You don't have to think up every attribute up front, but it helps to
|
|
15
|
+
sketch out a few so you can start working with the model immediately.
|
|
16
|
+
|
|
17
|
+
This generator invokes your configured ORM and test framework, which
|
|
18
|
+
defaults to Active Record and TestUnit.
|
|
19
|
+
|
|
20
|
+
Finally, if --parent option is given, it's used as superclass of the
|
|
21
|
+
created model. This allows you create Single Table Inheritance models.
|
|
22
|
+
|
|
23
|
+
If you pass a namespaced model name (e.g. admin/account or Admin::Account)
|
|
24
|
+
then the generator will create a module with a table_name_prefix method
|
|
25
|
+
to prefix the model's table name with the module name (e.g. admin_accounts)
|
|
26
|
+
|
|
27
|
+
Available field types:
|
|
28
|
+
|
|
29
|
+
Just after the field name you can specify a type like text or boolean.
|
|
30
|
+
It will generate the column with the associated SQL type. For instance:
|
|
31
|
+
|
|
32
|
+
`bin/rails generate model post title:string body:text`
|
|
33
|
+
|
|
34
|
+
will generate a title column with a varchar type and a body column with a text
|
|
35
|
+
type. If no type is specified the string type will be used by default.
|
|
36
|
+
You can use the following types:
|
|
37
|
+
|
|
38
|
+
integer
|
|
39
|
+
primary_key
|
|
40
|
+
decimal
|
|
41
|
+
float
|
|
42
|
+
boolean
|
|
43
|
+
binary
|
|
44
|
+
string
|
|
45
|
+
text
|
|
46
|
+
date
|
|
47
|
+
time
|
|
48
|
+
datetime
|
|
49
|
+
|
|
50
|
+
You can also consider `references` as a kind of type. For instance, if you run:
|
|
51
|
+
|
|
52
|
+
`bin/rails generate model photo title:string album:references`
|
|
53
|
+
|
|
54
|
+
It will generate an `album_id` column. You should generate these kinds of fields when
|
|
55
|
+
you will use a `belongs_to` association, for instance. `references` also supports
|
|
56
|
+
polymorphism, you can enable polymorphism like this:
|
|
57
|
+
|
|
58
|
+
`bin/rails generate model product supplier:references{polymorphic}`
|
|
59
|
+
|
|
60
|
+
For integer, string, text and binary fields, an integer in curly braces will
|
|
61
|
+
be set as the limit:
|
|
62
|
+
|
|
63
|
+
`bin/rails generate model user pseudo:string{30}`
|
|
64
|
+
|
|
65
|
+
For decimal, two integers separated by a comma in curly braces will be used
|
|
66
|
+
for precision and scale:
|
|
67
|
+
|
|
68
|
+
`bin/rails generate model product 'price:decimal{10,2}'`
|
|
69
|
+
|
|
70
|
+
You can add a `:uniq` or `:index` suffix for unique or standard indexes
|
|
71
|
+
respectively:
|
|
72
|
+
|
|
73
|
+
`bin/rails generate model user pseudo:string:uniq`
|
|
74
|
+
`bin/rails generate model user pseudo:string:index`
|
|
75
|
+
|
|
76
|
+
You can combine any single curly brace option with the index options:
|
|
77
|
+
|
|
78
|
+
`bin/rails generate model user username:string{30}:uniq`
|
|
79
|
+
`bin/rails generate model product supplier:references{polymorphic}:index`
|
|
80
|
+
|
|
81
|
+
If you require a `password_digest` string column for use with
|
|
82
|
+
has_secure_password, you can specify `password:digest`:
|
|
83
|
+
|
|
84
|
+
`bin/rails generate model user password:digest`
|
|
85
|
+
|
|
86
|
+
If you require a `token` string column for use with
|
|
87
|
+
has_secure_token, you can specify `auth_token:token`:
|
|
88
|
+
|
|
89
|
+
`bin/rails generate model user auth_token:token`
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
`bin/rails generate model account`
|
|
93
|
+
|
|
94
|
+
For Active Record and TestUnit it creates:
|
|
95
|
+
|
|
96
|
+
Model: app/models/account.rb
|
|
97
|
+
Test: test/models/account_test.rb
|
|
98
|
+
Fixtures: test/fixtures/accounts.yml
|
|
99
|
+
Migration: db/migrate/XXX_create_accounts.rb
|
|
100
|
+
|
|
101
|
+
`bin/rails generate model post title:string body:text published:boolean`
|
|
102
|
+
|
|
103
|
+
Creates a Post model with a string title, text body, and published flag.
|
|
104
|
+
|
|
105
|
+
`bin/rails generate model admin/account`
|
|
106
|
+
|
|
107
|
+
For Active Record and TestUnit it creates:
|
|
108
|
+
|
|
109
|
+
Module: app/models/admin.rb
|
|
110
|
+
Model: app/models/admin/account.rb
|
|
111
|
+
Test: test/models/admin/account_test.rb
|
|
112
|
+
Fixtures: test/fixtures/admin/accounts.yml
|
|
113
|
+
Migration: db/migrate/XXX_create_admin_accounts.rb
|
|
@@ -11,20 +11,25 @@ module ActiveRecord
|
|
|
11
11
|
|
|
12
12
|
class_option :migration, type: :boolean
|
|
13
13
|
class_option :timestamps, type: :boolean
|
|
14
|
-
class_option :parent, type: :string, desc: "The parent class for the generated model"
|
|
14
|
+
class_option :parent, type: :string, default: "ApplicationRecord", desc: "The parent class for the generated model"
|
|
15
15
|
class_option :indexes, type: :boolean, default: true, desc: "Add indexes for references and belongs_to columns"
|
|
16
16
|
class_option :primary_key_type, type: :string, desc: "The type for primary key"
|
|
17
17
|
class_option :database, type: :string, aliases: %i(--db), desc: "The database for your model's migration. By default, the current environment's primary database is used."
|
|
18
18
|
|
|
19
|
+
Rails::Generators.templates_path.each do |path|
|
|
20
|
+
source_paths << File.join(path, base_name, "migration")
|
|
21
|
+
end
|
|
22
|
+
source_paths << File.expand_path(File.join(base_name, "migration", "templates"), base_root)
|
|
23
|
+
|
|
19
24
|
# creates the migration file for the model.
|
|
20
25
|
def create_migration_file
|
|
21
26
|
return if skip_migration_creation?
|
|
22
27
|
attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
|
|
23
|
-
migration_template "
|
|
28
|
+
migration_template "create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def create_model_file
|
|
27
|
-
generate_abstract_class if database && !
|
|
32
|
+
generate_abstract_class if database && !custom_parent?
|
|
28
33
|
template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
|
|
29
34
|
end
|
|
30
35
|
|
|
@@ -40,7 +45,7 @@ module ActiveRecord
|
|
|
40
45
|
# - options parent is present and database option is not present
|
|
41
46
|
# - migrations option is nil or false
|
|
42
47
|
def skip_migration_creation?
|
|
43
|
-
|
|
48
|
+
custom_parent? && !database || !migration
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
def attributes_with_index
|
|
@@ -49,12 +54,12 @@ module ActiveRecord
|
|
|
49
54
|
|
|
50
55
|
# Used by the migration template to determine the parent name of the model
|
|
51
56
|
def parent_class_name
|
|
52
|
-
if
|
|
57
|
+
if custom_parent?
|
|
53
58
|
parent
|
|
54
59
|
elsif database
|
|
55
60
|
abstract_class_name
|
|
56
61
|
else
|
|
57
|
-
|
|
62
|
+
parent
|
|
58
63
|
end
|
|
59
64
|
end
|
|
60
65
|
|
|
@@ -77,6 +82,10 @@ module ActiveRecord
|
|
|
77
82
|
options[:parent]
|
|
78
83
|
end
|
|
79
84
|
|
|
85
|
+
def custom_parent?
|
|
86
|
+
parent != self.class.class_options[:parent].default
|
|
87
|
+
end
|
|
88
|
+
|
|
80
89
|
def migration
|
|
81
90
|
options[:migration]
|
|
82
91
|
end
|