activerecord 8.0.2 → 8.1.0.beta1
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 +459 -413
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +9 -1
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +3 -3
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/join_dependency.rb +2 -0
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations.rb +159 -21
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +17 -4
- data/lib/active_record/attributes.rb +38 -24
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +15 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +384 -49
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +26 -30
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +19 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -34
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +89 -23
- data/lib/active_record/connection_adapters/abstract/transaction.rb +16 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +67 -13
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -11
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +26 -4
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +27 -22
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -16
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +8 -21
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +65 -30
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +74 -38
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -7
- data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -27
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +56 -32
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +4 -3
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
- data/lib/active_record/connection_adapters.rb +1 -0
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +13 -10
- data/lib/active_record/counter_cache.rb +33 -8
- data/lib/active_record/database_configurations/database_config.rb +5 -1
- data/lib/active_record/database_configurations/hash_config.rb +56 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +2 -2
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encryptor.rb +27 -25
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +37 -20
- data/lib/active_record/errors.rb +20 -4
- data/lib/active_record/explain_registry.rb +0 -1
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- data/lib/active_record/locking/optimistic.rb +7 -0
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +1 -5
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +14 -1
- data/lib/active_record/migration/compatibility.rb +34 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +31 -21
- data/lib/active_record/model_schema.rb +10 -7
- data/lib/active_record/nested_attributes.rb +2 -0
- data/lib/active_record/persistence.rb +34 -3
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +7 -7
- data/lib/active_record/querying.rb +4 -4
- data/lib/active_record/railtie.rb +34 -5
- data/lib/active_record/railties/databases.rake +23 -19
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +42 -3
- data/lib/active_record/relation/batches.rb +26 -12
- data/lib/active_record/relation/calculations.rb +35 -25
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +41 -24
- data/lib/active_record/relation/merger.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +2 -2
- data/lib/active_record/relation/query_attribute.rb +3 -1
- data/lib/active_record/relation/query_methods.rb +43 -33
- data/lib/active_record/relation/spawn_methods.rb +6 -6
- data/lib/active_record/relation/where_clause.rb +7 -10
- data/lib/active_record/relation.rb +37 -15
- data/lib/active_record/result.rb +44 -21
- data/lib/active_record/sanitization.rb +2 -0
- data/lib/active_record/schema_dumper.rb +12 -10
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +46 -18
- data/lib/active_record/statement_cache.rb +13 -9
- data/lib/active_record/store.rb +44 -19
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +24 -35
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -40
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
- data/lib/active_record/test_databases.rb +11 -3
- data/lib/active_record/test_fixtures.rb +27 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +34 -10
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +11 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record.rb +68 -5
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +5 -21
- data/lib/arel.rb +3 -1
- metadata +15 -11
- data/lib/active_record/normalization.rb +0 -163
data/lib/arel/visitors/sqlite.rb
CHANGED
@@ -4,6 +4,61 @@ module Arel # :nodoc: all
|
|
4
4
|
module Visitors
|
5
5
|
class SQLite < Arel::Visitors::ToSql
|
6
6
|
private
|
7
|
+
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
8
|
+
collector.retryable = false
|
9
|
+
o = prepare_update_statement(o)
|
10
|
+
|
11
|
+
collector << "UPDATE "
|
12
|
+
|
13
|
+
# UPDATE with JOIN is in the form of:
|
14
|
+
#
|
15
|
+
# UPDATE t1 AS __active_record_update_alias
|
16
|
+
# SET ..
|
17
|
+
# FROM t1 JOIN t2 ON t2.join_id = t1.join_id ..
|
18
|
+
# WHERE t1.id = __active_record_update_alias.id AND ..
|
19
|
+
if has_join_sources?(o)
|
20
|
+
collector = visit o.relation.left, collector
|
21
|
+
collect_nodes_for o.values, collector, " SET "
|
22
|
+
collector << " FROM "
|
23
|
+
collector = inject_join o.relation.right, collector, " "
|
24
|
+
else
|
25
|
+
collector = visit o.relation, collector
|
26
|
+
collect_nodes_for o.values, collector, " SET "
|
27
|
+
end
|
28
|
+
|
29
|
+
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
30
|
+
collect_nodes_for o.orders, collector, " ORDER BY "
|
31
|
+
maybe_visit o.limit, collector
|
32
|
+
maybe_visit o.comment, collector
|
33
|
+
end
|
34
|
+
|
35
|
+
def prepare_update_statement(o)
|
36
|
+
# Sqlite need to be built with the SQLITE_ENABLE_UPDATE_DELETE_LIMIT compile-time option
|
37
|
+
# to support LIMIT/OFFSET/ORDER in UPDATE and DELETE statements.
|
38
|
+
if o.key && has_join_sources?(o) && !has_group_by_and_having?(o) && !has_limit_or_offset_or_orders?(o)
|
39
|
+
# Join clauses cannot reference the target table, so alias the
|
40
|
+
# updated table, place the entire relation in the FROM clause, and
|
41
|
+
# add a self-join (which requires the primary key)
|
42
|
+
stmt = o.clone
|
43
|
+
stmt.relation, stmt.wheres = o.relation.clone, o.wheres.clone
|
44
|
+
stmt.relation.right = [stmt.relation.left, *stmt.relation.right]
|
45
|
+
stmt.relation.left = stmt.relation.left.alias("__active_record_update_alias")
|
46
|
+
Array.wrap(o.key).each do |key|
|
47
|
+
stmt.wheres << key.eq(stmt.relation.left[key.name])
|
48
|
+
end
|
49
|
+
stmt
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def visit_Arel_Nodes_TableAlias(o, collector)
|
56
|
+
# "AS" is not optional in "{UPDATE | DELETE} table AS alias ..."
|
57
|
+
collector = visit o.relation, collector
|
58
|
+
collector << " AS "
|
59
|
+
collector << quote_table_name(o.name)
|
60
|
+
end
|
61
|
+
|
7
62
|
# Locks are not supported in SQLite
|
8
63
|
def visit_Arel_Nodes_Lock(o, collector)
|
9
64
|
collector
|
@@ -14,14 +69,6 @@ module Arel # :nodoc: all
|
|
14
69
|
super
|
15
70
|
end
|
16
71
|
|
17
|
-
def visit_Arel_Nodes_True(o, collector)
|
18
|
-
collector << "1"
|
19
|
-
end
|
20
|
-
|
21
|
-
def visit_Arel_Nodes_False(o, collector)
|
22
|
-
collector << "0"
|
23
|
-
end
|
24
|
-
|
25
72
|
def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
|
26
73
|
collector = visit o.left, collector
|
27
74
|
collector << " IS "
|
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -35,6 +35,7 @@ module Arel # :nodoc: all
|
|
35
35
|
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
36
36
|
collect_nodes_for o.orders, collector, " ORDER BY "
|
37
37
|
maybe_visit o.limit, collector
|
38
|
+
maybe_visit o.comment, collector
|
38
39
|
end
|
39
40
|
|
40
41
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
@@ -48,6 +49,7 @@ module Arel # :nodoc: all
|
|
48
49
|
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
49
50
|
collect_nodes_for o.orders, collector, " ORDER BY "
|
50
51
|
maybe_visit o.limit, collector
|
52
|
+
maybe_visit o.comment, collector
|
51
53
|
end
|
52
54
|
|
53
55
|
def visit_Arel_Nodes_InsertStatement(o, collector)
|
@@ -75,13 +77,7 @@ module Arel # :nodoc: all
|
|
75
77
|
|
76
78
|
def visit_Arel_Nodes_Exists(o, collector)
|
77
79
|
collector << "EXISTS ("
|
78
|
-
|
79
|
-
if o.alias
|
80
|
-
collector << " AS "
|
81
|
-
visit o.alias, collector
|
82
|
-
else
|
83
|
-
collector
|
84
|
-
end
|
80
|
+
visit(o.expressions, collector) << ")"
|
85
81
|
end
|
86
82
|
|
87
83
|
def visit_Arel_Nodes_Casted(o, collector)
|
@@ -388,13 +384,7 @@ module Arel # :nodoc: all
|
|
388
384
|
collector << o.name
|
389
385
|
collector << "("
|
390
386
|
collector << "DISTINCT " if o.distinct
|
391
|
-
|
392
|
-
if o.alias
|
393
|
-
collector << " AS "
|
394
|
-
visit o.alias, collector
|
395
|
-
else
|
396
|
-
collector
|
397
|
-
end
|
387
|
+
inject_join(o.expressions, collector, ", ") << ")"
|
398
388
|
end
|
399
389
|
|
400
390
|
def visit_Arel_Nodes_Extract(o, collector)
|
@@ -998,13 +988,7 @@ module Arel # :nodoc: all
|
|
998
988
|
if o.distinct
|
999
989
|
collector << "DISTINCT "
|
1000
990
|
end
|
1001
|
-
|
1002
|
-
if o.alias
|
1003
|
-
collector << " AS "
|
1004
|
-
visit o.alias, collector
|
1005
|
-
else
|
1006
|
-
collector
|
1007
|
-
end
|
991
|
+
inject_join(o.expressions, collector, ", ") << ")"
|
1008
992
|
end
|
1009
993
|
|
1010
994
|
def is_distinct_from(o, collector)
|
data/lib/arel.rb
CHANGED
@@ -50,7 +50,9 @@ module Arel
|
|
50
50
|
# Use this option only if the SQL is idempotent, as it could be executed
|
51
51
|
# more than once.
|
52
52
|
def self.sql(sql_string, *positional_binds, retryable: false, **named_binds)
|
53
|
-
if
|
53
|
+
if Arel::Nodes::SqlLiteral === sql_string
|
54
|
+
sql_string
|
55
|
+
elsif positional_binds.empty? && named_binds.empty?
|
54
56
|
Arel::Nodes::SqlLiteral.new(sql_string, retryable: retryable)
|
55
57
|
else
|
56
58
|
Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.0.
|
4
|
+
version: 8.1.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activesupport
|
@@ -15,28 +15,28 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - '='
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 8.0.
|
18
|
+
version: 8.1.0.beta1
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - '='
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: 8.0.
|
25
|
+
version: 8.1.0.beta1
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: activemodel
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - '='
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 8.0.
|
32
|
+
version: 8.1.0.beta1
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - '='
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 8.0.
|
39
|
+
version: 8.1.0.beta1
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: timeout
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,6 +83,7 @@ files:
|
|
83
83
|
- lib/active_record/associations/builder/singular_association.rb
|
84
84
|
- lib/active_record/associations/collection_association.rb
|
85
85
|
- lib/active_record/associations/collection_proxy.rb
|
86
|
+
- lib/active_record/associations/deprecation.rb
|
86
87
|
- lib/active_record/associations/disable_joins_association_scope.rb
|
87
88
|
- lib/active_record/associations/errors.rb
|
88
89
|
- lib/active_record/associations/foreign_association.rb
|
@@ -253,6 +254,7 @@ files:
|
|
253
254
|
- lib/active_record/explain.rb
|
254
255
|
- lib/active_record/explain_registry.rb
|
255
256
|
- lib/active_record/explain_subscriber.rb
|
257
|
+
- lib/active_record/filter_attribute_handler.rb
|
256
258
|
- lib/active_record/fixture_set/file.rb
|
257
259
|
- lib/active_record/fixture_set/model_metadata.rb
|
258
260
|
- lib/active_record/fixture_set/render_context.rb
|
@@ -279,6 +281,7 @@ files:
|
|
279
281
|
- lib/active_record/migration.rb
|
280
282
|
- lib/active_record/migration/command_recorder.rb
|
281
283
|
- lib/active_record/migration/compatibility.rb
|
284
|
+
- lib/active_record/migration/default_schema_versions_formatter.rb
|
282
285
|
- lib/active_record/migration/default_strategy.rb
|
283
286
|
- lib/active_record/migration/execution_strategy.rb
|
284
287
|
- lib/active_record/migration/join_table.rb
|
@@ -286,7 +289,6 @@ files:
|
|
286
289
|
- lib/active_record/model_schema.rb
|
287
290
|
- lib/active_record/nested_attributes.rb
|
288
291
|
- lib/active_record/no_touching.rb
|
289
|
-
- lib/active_record/normalization.rb
|
290
292
|
- lib/active_record/persistence.rb
|
291
293
|
- lib/active_record/promise.rb
|
292
294
|
- lib/active_record/query_cache.rb
|
@@ -297,6 +299,7 @@ files:
|
|
297
299
|
- lib/active_record/railties/console_sandbox.rb
|
298
300
|
- lib/active_record/railties/controller_runtime.rb
|
299
301
|
- lib/active_record/railties/databases.rake
|
302
|
+
- lib/active_record/railties/job_checkpoints.rb
|
300
303
|
- lib/active_record/railties/job_runtime.rb
|
301
304
|
- lib/active_record/readonly_attributes.rb
|
302
305
|
- lib/active_record/reflection.rb
|
@@ -336,6 +339,7 @@ files:
|
|
336
339
|
- lib/active_record/store.rb
|
337
340
|
- lib/active_record/suppressor.rb
|
338
341
|
- lib/active_record/table_metadata.rb
|
342
|
+
- lib/active_record/tasks/abstract_tasks.rb
|
339
343
|
- lib/active_record/tasks/database_tasks.rb
|
340
344
|
- lib/active_record/tasks/mysql_database_tasks.rb
|
341
345
|
- lib/active_record/tasks/postgresql_database_tasks.rb
|
@@ -474,10 +478,10 @@ licenses:
|
|
474
478
|
- MIT
|
475
479
|
metadata:
|
476
480
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
477
|
-
changelog_uri: https://github.com/rails/rails/blob/v8.0.
|
478
|
-
documentation_uri: https://api.rubyonrails.org/v8.0.
|
481
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.1.0.beta1/activerecord/CHANGELOG.md
|
482
|
+
documentation_uri: https://api.rubyonrails.org/v8.1.0.beta1/
|
479
483
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
480
|
-
source_code_uri: https://github.com/rails/rails/tree/v8.0.
|
484
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.1.0.beta1/activerecord
|
481
485
|
rubygems_mfa_required: 'true'
|
482
486
|
rdoc_options:
|
483
487
|
- "--main"
|
@@ -495,7 +499,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
495
499
|
- !ruby/object:Gem::Version
|
496
500
|
version: '0'
|
497
501
|
requirements: []
|
498
|
-
rubygems_version: 3.6.
|
502
|
+
rubygems_version: 3.6.9
|
499
503
|
specification_version: 4
|
500
504
|
summary: Object-relational mapper framework (part of Rails).
|
501
505
|
test_files: []
|
@@ -1,163 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecord # :nodoc:
|
4
|
-
module Normalization
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
included do
|
8
|
-
class_attribute :normalized_attributes, default: Set.new
|
9
|
-
|
10
|
-
before_validation :normalize_changed_in_place_attributes
|
11
|
-
end
|
12
|
-
|
13
|
-
# Normalizes a specified attribute using its declared normalizations.
|
14
|
-
#
|
15
|
-
# ==== Examples
|
16
|
-
#
|
17
|
-
# class User < ActiveRecord::Base
|
18
|
-
# normalizes :email, with: -> email { email.strip.downcase }
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# legacy_user = User.find(1)
|
22
|
-
# legacy_user.email # => " CRUISE-CONTROL@EXAMPLE.COM\n"
|
23
|
-
# legacy_user.normalize_attribute(:email)
|
24
|
-
# legacy_user.email # => "cruise-control@example.com"
|
25
|
-
# legacy_user.save
|
26
|
-
def normalize_attribute(name)
|
27
|
-
# Treat the value as a new, unnormalized value.
|
28
|
-
self[name] = self[name]
|
29
|
-
end
|
30
|
-
|
31
|
-
module ClassMethods
|
32
|
-
# Declares a normalization for one or more attributes. The normalization
|
33
|
-
# is applied when the attribute is assigned or updated, and the normalized
|
34
|
-
# value will be persisted to the database. The normalization is also
|
35
|
-
# applied to the corresponding keyword argument of query methods. This
|
36
|
-
# allows a record to be created and later queried using unnormalized
|
37
|
-
# values.
|
38
|
-
#
|
39
|
-
# However, to prevent confusion, the normalization will not be applied
|
40
|
-
# when the attribute is fetched from the database. This means that if a
|
41
|
-
# record was persisted before the normalization was declared, the record's
|
42
|
-
# attribute will not be normalized until either it is assigned a new
|
43
|
-
# value, or it is explicitly migrated via Normalization#normalize_attribute.
|
44
|
-
#
|
45
|
-
# Because the normalization may be applied multiple times, it should be
|
46
|
-
# _idempotent_. In other words, applying the normalization more than once
|
47
|
-
# should have the same result as applying it only once.
|
48
|
-
#
|
49
|
-
# By default, the normalization will not be applied to +nil+ values. This
|
50
|
-
# behavior can be changed with the +:apply_to_nil+ option.
|
51
|
-
#
|
52
|
-
# Be aware that if your app was created before Rails 7.1, and your app
|
53
|
-
# marshals instances of the targeted model (for example, when caching),
|
54
|
-
# then you should set ActiveRecord.marshalling_format_version to +7.1+ or
|
55
|
-
# higher via either <tt>config.load_defaults 7.1</tt> or
|
56
|
-
# <tt>config.active_record.marshalling_format_version = 7.1</tt>.
|
57
|
-
# Otherwise, +Marshal+ may attempt to serialize the normalization +Proc+
|
58
|
-
# and raise +TypeError+.
|
59
|
-
#
|
60
|
-
# ==== Options
|
61
|
-
#
|
62
|
-
# * +:with+ - Any callable object that accepts the attribute's value as
|
63
|
-
# its sole argument, and returns it normalized.
|
64
|
-
# * +:apply_to_nil+ - Whether to apply the normalization to +nil+ values.
|
65
|
-
# Defaults to +false+.
|
66
|
-
#
|
67
|
-
# ==== Examples
|
68
|
-
#
|
69
|
-
# class User < ActiveRecord::Base
|
70
|
-
# normalizes :email, with: -> email { email.strip.downcase }
|
71
|
-
# normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") }
|
72
|
-
# end
|
73
|
-
#
|
74
|
-
# user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n")
|
75
|
-
# user.email # => "cruise-control@example.com"
|
76
|
-
#
|
77
|
-
# user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")
|
78
|
-
# user.email # => "cruise-control@example.com"
|
79
|
-
# user.email_before_type_cast # => "cruise-control@example.com"
|
80
|
-
#
|
81
|
-
# User.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count # => 1
|
82
|
-
# User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0
|
83
|
-
#
|
84
|
-
# User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") # => true
|
85
|
-
# User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
|
86
|
-
#
|
87
|
-
# User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
|
88
|
-
def normalizes(*names, with:, apply_to_nil: false)
|
89
|
-
decorate_attributes(names) do |name, cast_type|
|
90
|
-
NormalizedValueType.new(cast_type: cast_type, normalizer: with, normalize_nil: apply_to_nil)
|
91
|
-
end
|
92
|
-
|
93
|
-
self.normalized_attributes += names.map(&:to_sym)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Normalizes a given +value+ using normalizations declared for +name+.
|
97
|
-
#
|
98
|
-
# ==== Examples
|
99
|
-
#
|
100
|
-
# class User < ActiveRecord::Base
|
101
|
-
# normalizes :email, with: -> email { email.strip.downcase }
|
102
|
-
# end
|
103
|
-
#
|
104
|
-
# User.normalize_value_for(:email, " CRUISE-CONTROL@EXAMPLE.COM\n")
|
105
|
-
# # => "cruise-control@example.com"
|
106
|
-
def normalize_value_for(name, value)
|
107
|
-
type_for_attribute(name).cast(value)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
def normalize_changed_in_place_attributes
|
113
|
-
self.class.normalized_attributes.each do |name|
|
114
|
-
normalize_attribute(name) if attribute_changed_in_place?(name)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class NormalizedValueType < DelegateClass(ActiveModel::Type::Value) # :nodoc:
|
119
|
-
include ActiveModel::Type::SerializeCastValue
|
120
|
-
|
121
|
-
attr_reader :cast_type, :normalizer, :normalize_nil
|
122
|
-
alias :normalize_nil? :normalize_nil
|
123
|
-
|
124
|
-
def initialize(cast_type:, normalizer:, normalize_nil:)
|
125
|
-
@cast_type = cast_type
|
126
|
-
@normalizer = normalizer
|
127
|
-
@normalize_nil = normalize_nil
|
128
|
-
super(cast_type)
|
129
|
-
end
|
130
|
-
|
131
|
-
def cast(value)
|
132
|
-
normalize(super(value))
|
133
|
-
end
|
134
|
-
|
135
|
-
def serialize(value)
|
136
|
-
serialize_cast_value(cast(value))
|
137
|
-
end
|
138
|
-
|
139
|
-
def serialize_cast_value(value)
|
140
|
-
ActiveModel::Type::SerializeCastValue.serialize(cast_type, value)
|
141
|
-
end
|
142
|
-
|
143
|
-
def ==(other)
|
144
|
-
self.class == other.class &&
|
145
|
-
normalize_nil? == other.normalize_nil? &&
|
146
|
-
normalizer == other.normalizer &&
|
147
|
-
cast_type == other.cast_type
|
148
|
-
end
|
149
|
-
alias eql? ==
|
150
|
-
|
151
|
-
def hash
|
152
|
-
[self.class, cast_type, normalizer, normalize_nil?].hash
|
153
|
-
end
|
154
|
-
|
155
|
-
define_method(:inspect, Kernel.instance_method(:inspect))
|
156
|
-
|
157
|
-
private
|
158
|
-
def normalize(value)
|
159
|
-
normalizer.call(value) unless value.nil? && !normalize_nil?
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|