activerecord 4.2.8 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +612 -1583
- data/MIT-LICENSE +4 -2
- data/README.rdoc +13 -12
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record.rb +41 -22
- data/lib/active_record/aggregations.rb +267 -251
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations.rb +1737 -1597
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +125 -58
- data/lib/active_record/associations/association_scope.rb +103 -132
- data/lib/active_record/associations/belongs_to_association.rb +65 -60
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +27 -40
- data/lib/active_record/associations/builder/belongs_to.rb +69 -55
- data/lib/active_record/associations/builder/collection_association.rb +10 -33
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
- data/lib/active_record/associations/builder/has_many.rb +8 -4
- data/lib/active_record/associations/builder/has_one.rb +46 -5
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +134 -286
- data/lib/active_record/associations/collection_proxy.rb +241 -146
- data/lib/active_record/associations/foreign_association.rb +10 -1
- data/lib/active_record/associations/has_many_association.rb +34 -97
- data/lib/active_record/associations/has_many_through_association.rb +60 -87
- data/lib/active_record/associations/has_one_association.rb +61 -49
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +137 -167
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -88
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/preloader.rb +90 -92
- data/lib/active_record/associations/preloader/association.rb +90 -123
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/attribute_assignment.rb +56 -183
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods.rb +120 -135
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
- data/lib/active_record/attribute_methods/dirty.rb +174 -144
- data/lib/active_record/attribute_methods/primary_key.rb +91 -83
- data/lib/active_record/attribute_methods/query.rb +6 -5
- data/lib/active_record/attribute_methods/read.rb +20 -76
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
- data/lib/active_record/attribute_methods/write.rb +32 -54
- data/lib/active_record/attributes.rb +214 -82
- data/lib/active_record/autosave_association.rb +91 -37
- data/lib/active_record/base.rb +57 -45
- data/lib/active_record/callbacks.rb +100 -74
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -296
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -244
- data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
- data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -627
- data/lib/active_record/connection_adapters/column.rb +56 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -188
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +551 -356
- data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -345
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +176 -41
- data/lib/active_record/core.rb +251 -231
- data/lib/active_record/counter_cache.rb +67 -49
- data/lib/active_record/database_configurations.rb +233 -0
- 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/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +163 -86
- data/lib/active_record/errors.rb +188 -53
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- 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 +228 -499
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +158 -112
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +123 -29
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +87 -96
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +76 -33
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +626 -283
- data/lib/active_record/migration/command_recorder.rb +177 -90
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/model_schema.rb +314 -112
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +14 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +557 -125
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +43 -29
- data/lib/active_record/railtie.rb +147 -46
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +330 -197
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +428 -279
- data/lib/active_record/relation.rb +518 -341
- data/lib/active_record/relation/batches.rb +207 -55
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +267 -253
- data/lib/active_record/relation/delegation.rb +70 -80
- data/lib/active_record/relation/finder_methods.rb +277 -241
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +78 -87
- data/lib/active_record/relation/predicate_builder.rb +114 -119
- data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +575 -394
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- data/lib/active_record/relation/where_clause.rb +190 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/result.rb +79 -42
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +144 -121
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +112 -93
- data/lib/active_record/schema_migration.rb +24 -17
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/scoping/default.rb +101 -85
- data/lib/active_record/scoping/named.rb +86 -33
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +73 -36
- data/lib/active_record/store.rb +127 -42
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +75 -0
- data/lib/active_record/tasks/database_tasks.rb +308 -99
- data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
- data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +86 -40
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +216 -150
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +78 -23
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +24 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -0
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +42 -55
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -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.rb +68 -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/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.rb +20 -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/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +7 -5
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration.rb +31 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +164 -60
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -58
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/per_thread_registry"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
# This is a thread locals registry for Active Record. For example:
|
@@ -7,14 +9,14 @@ module ActiveRecord
|
|
7
9
|
#
|
8
10
|
# returns the connection handler local to the current thread.
|
9
11
|
#
|
10
|
-
# See the documentation of
|
12
|
+
# See the documentation of ActiveSupport::PerThreadRegistry
|
11
13
|
# for further details.
|
12
14
|
class RuntimeRegistry # :nodoc:
|
13
15
|
extend ActiveSupport::PerThreadRegistry
|
14
16
|
|
15
|
-
attr_accessor :connection_handler, :sql_runtime
|
17
|
+
attr_accessor :connection_handler, :sql_runtime
|
16
18
|
|
17
|
-
[:connection_handler, :sql_runtime
|
19
|
+
[:connection_handler, :sql_runtime].each do |val|
|
18
20
|
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
19
21
|
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
20
22
|
end
|
@@ -1,40 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Sanitization
|
3
5
|
extend ActiveSupport::Concern
|
4
6
|
|
5
7
|
module ClassMethods
|
6
|
-
|
7
|
-
connection.quote(value, column)
|
8
|
-
end
|
9
|
-
|
10
|
-
# Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>.
|
11
|
-
def sanitize(object) #:nodoc:
|
12
|
-
connection.quote(object)
|
13
|
-
end
|
14
|
-
|
15
|
-
protected
|
16
|
-
|
17
|
-
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
8
|
+
# Accepts an array or string of SQL conditions and sanitizes
|
18
9
|
# them into a valid SQL fragment for a WHERE clause.
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
10
|
+
#
|
11
|
+
# sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4])
|
12
|
+
# # => "name='foo''bar' and group_id=4"
|
13
|
+
#
|
14
|
+
# sanitize_sql_for_conditions(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
15
|
+
# # => "name='foo''bar' and group_id='4'"
|
16
|
+
#
|
17
|
+
# sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4])
|
18
|
+
# # => "name='foo''bar' and group_id='4'"
|
19
|
+
#
|
20
|
+
# sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
|
21
|
+
# # => "name='foo''bar' and group_id='4'"
|
22
|
+
def sanitize_sql_for_conditions(condition)
|
23
23
|
return nil if condition.blank?
|
24
24
|
|
25
25
|
case condition
|
26
26
|
when Array; sanitize_sql_array(condition)
|
27
|
-
when Hash; sanitize_sql_hash_for_conditions(condition, table_name)
|
28
27
|
else condition
|
29
28
|
end
|
30
29
|
end
|
31
|
-
|
32
|
-
alias_method :sanitize_conditions, :sanitize_sql
|
30
|
+
alias :sanitize_sql :sanitize_sql_for_conditions
|
33
31
|
|
34
32
|
# Accepts an array, hash, or string of SQL conditions and sanitizes
|
35
33
|
# them into a valid SQL fragment for a SET clause.
|
36
|
-
#
|
37
|
-
|
34
|
+
#
|
35
|
+
# sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4])
|
36
|
+
# # => "name=NULL and group_id=4"
|
37
|
+
#
|
38
|
+
# sanitize_sql_for_assignment(["name=:name and group_id=:group_id", name: nil, group_id: 4])
|
39
|
+
# # => "name=NULL and group_id=4"
|
40
|
+
#
|
41
|
+
# Post.sanitize_sql_for_assignment({ name: nil, group_id: 4 })
|
42
|
+
# # => "`posts`.`name` = NULL, `posts`.`group_id` = 4"
|
43
|
+
#
|
44
|
+
# sanitize_sql_for_assignment("name=NULL and group_id='4'")
|
45
|
+
# # => "name=NULL and group_id='4'"
|
46
|
+
def sanitize_sql_for_assignment(assignments, default_table_name = table_name)
|
38
47
|
case assignments
|
39
48
|
when Array; sanitize_sql_array(assignments)
|
40
49
|
when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
|
@@ -42,76 +51,60 @@ module ActiveRecord
|
|
42
51
|
end
|
43
52
|
end
|
44
53
|
|
45
|
-
# Accepts
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
else
|
65
|
-
expanded_attrs[field_attr] = value.send(aggregate_attr)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
else
|
69
|
-
expanded_attrs[attr] = value
|
54
|
+
# Accepts an array, or string of SQL conditions and sanitizes
|
55
|
+
# them into a valid SQL fragment for an ORDER clause.
|
56
|
+
#
|
57
|
+
# sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
|
58
|
+
# # => "field(id, 1,3,2)"
|
59
|
+
#
|
60
|
+
# sanitize_sql_for_order("id ASC")
|
61
|
+
# # => "id ASC"
|
62
|
+
def sanitize_sql_for_order(condition)
|
63
|
+
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
64
|
+
disallow_raw_sql!(
|
65
|
+
[condition.first],
|
66
|
+
permit: connection.column_name_with_order_matcher
|
67
|
+
)
|
68
|
+
|
69
|
+
# Ensure we aren't dealing with a subclass of String that might
|
70
|
+
# override methods we use (eg. Arel::Nodes::SqlLiteral).
|
71
|
+
if condition.first.kind_of?(String) && !condition.first.instance_of?(String)
|
72
|
+
condition = [String.new(condition.first), *condition[1..-1]]
|
70
73
|
end
|
71
|
-
end
|
72
|
-
expanded_attrs
|
73
|
-
end
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# # => "status IS NULL and group_id IN (1,2,3)"
|
80
|
-
# { age: 13..18 }
|
81
|
-
# # => "age BETWEEN 13 AND 18"
|
82
|
-
# { 'other_records.id' => 7 }
|
83
|
-
# # => "`other_records`.`id` = 7"
|
84
|
-
# { other_records: { id: 7 } }
|
85
|
-
# # => "`other_records`.`id` = 7"
|
86
|
-
# And for value objects on a composed_of relationship:
|
87
|
-
# { address: Address.new("123 abc st.", "chicago") }
|
88
|
-
# # => "address_street='123 abc st.' and address_city='chicago'"
|
89
|
-
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
|
90
|
-
ActiveSupport::Deprecation.warn(<<-EOWARN)
|
91
|
-
sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
|
92
|
-
EOWARN
|
93
|
-
attrs = PredicateBuilder.resolve_column_aliases self, attrs
|
94
|
-
attrs = expand_hash_conditions_for_aggregates(attrs)
|
95
|
-
|
96
|
-
table = Arel::Table.new(table_name, arel_engine).alias(default_table_name)
|
97
|
-
PredicateBuilder.build_from_hash(self, attrs, table).map { |b|
|
98
|
-
connection.visitor.compile b
|
99
|
-
}.join(' AND ')
|
75
|
+
Arel.sql(sanitize_sql_array(condition))
|
76
|
+
else
|
77
|
+
condition
|
78
|
+
end
|
100
79
|
end
|
101
|
-
alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
|
102
80
|
|
103
81
|
# Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
|
104
|
-
#
|
105
|
-
#
|
82
|
+
#
|
83
|
+
# sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts")
|
84
|
+
# # => "`posts`.`status` = NULL, `posts`.`group_id` = 1"
|
106
85
|
def sanitize_sql_hash_for_assignment(attrs, table)
|
107
86
|
c = connection
|
108
87
|
attrs.map do |attr, value|
|
109
|
-
|
110
|
-
|
88
|
+
type = type_for_attribute(attr)
|
89
|
+
value = type.serialize(type.cast(value))
|
90
|
+
"#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
|
91
|
+
end.join(", ")
|
111
92
|
end
|
112
93
|
|
113
94
|
# Sanitizes a +string+ so that it is safe to use within an SQL
|
114
|
-
# LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%"
|
95
|
+
# LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
|
96
|
+
#
|
97
|
+
# sanitize_sql_like("100%")
|
98
|
+
# # => "100\\%"
|
99
|
+
#
|
100
|
+
# sanitize_sql_like("snake_cased_string")
|
101
|
+
# # => "snake\\_cased\\_string"
|
102
|
+
#
|
103
|
+
# sanitize_sql_like("100%", "!")
|
104
|
+
# # => "100!%"
|
105
|
+
#
|
106
|
+
# sanitize_sql_like("snake_cased_string", "!")
|
107
|
+
# # => "snake!_cased!_string"
|
115
108
|
def sanitize_sql_like(string, escape_character = "\\")
|
116
109
|
pattern = Regexp.union(escape_character, "%", "_")
|
117
110
|
string.gsub(pattern) { |x| [escape_character, x].join }
|
@@ -119,12 +112,20 @@ sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
|
|
119
112
|
|
120
113
|
# Accepts an array of conditions. The array has each value
|
121
114
|
# sanitized and interpolated into the SQL statement.
|
122
|
-
#
|
115
|
+
#
|
116
|
+
# sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4])
|
117
|
+
# # => "name='foo''bar' and group_id=4"
|
118
|
+
#
|
119
|
+
# sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4])
|
120
|
+
# # => "name='foo''bar' and group_id=4"
|
121
|
+
#
|
122
|
+
# sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
|
123
|
+
# # => "name='foo''bar' and group_id='4'"
|
123
124
|
def sanitize_sql_array(ary)
|
124
125
|
statement, *values = ary
|
125
|
-
if values.first.is_a?(Hash) &&
|
126
|
+
if values.first.is_a?(Hash) && /:\w+/.match?(statement)
|
126
127
|
replace_named_bind_variables(statement, values.first)
|
127
|
-
elsif statement.include?(
|
128
|
+
elsif statement.include?("?")
|
128
129
|
replace_bind_variables(statement, values)
|
129
130
|
elsif statement.blank?
|
130
131
|
statement
|
@@ -133,59 +134,81 @@ sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
|
|
133
134
|
end
|
134
135
|
end
|
135
136
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
replace_bind_variable(bound.shift, c)
|
137
|
+
def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
|
138
|
+
unexpected = nil
|
139
|
+
args.each do |arg|
|
140
|
+
next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
|
141
|
+
(unexpected ||= []) << arg
|
142
142
|
end
|
143
|
-
end
|
144
143
|
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
return unless unexpected
|
145
|
+
|
146
|
+
if allow_unsafe_raw_sql == :deprecated
|
147
|
+
ActiveSupport::Deprecation.warn(
|
148
|
+
"Dangerous query method (method whose arguments are used as raw " \
|
149
|
+
"SQL) called with non-attribute argument(s): " \
|
150
|
+
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
151
|
+
"arguments will be disallowed in Rails 6.1. This method should " \
|
152
|
+
"not be called with user-provided values, such as request " \
|
153
|
+
"parameters or model attributes. Known-safe values can be passed " \
|
154
|
+
"by wrapping them in Arel.sql()."
|
155
|
+
)
|
148
156
|
else
|
149
|
-
|
157
|
+
raise(ActiveRecord::UnknownAttributeReference,
|
158
|
+
"Query method called with non-attribute argument(s): " +
|
159
|
+
unexpected.map(&:inspect).join(", ")
|
160
|
+
)
|
150
161
|
end
|
151
162
|
end
|
152
163
|
|
153
|
-
|
154
|
-
statement
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
164
|
+
private
|
165
|
+
def replace_bind_variables(statement, values)
|
166
|
+
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
|
167
|
+
bound = values.dup
|
168
|
+
c = connection
|
169
|
+
statement.gsub(/\?/) do
|
170
|
+
replace_bind_variable(bound.shift, c)
|
161
171
|
end
|
162
172
|
end
|
163
|
-
end
|
164
173
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
elsif value.respond_to?(:map) && !value.acts_like?(:string)
|
169
|
-
if value.respond_to?(:empty?) && value.empty?
|
170
|
-
c.quote(nil)
|
174
|
+
def replace_bind_variable(value, c = connection)
|
175
|
+
if ActiveRecord::Relation === value
|
176
|
+
value.to_sql
|
171
177
|
else
|
172
|
-
value
|
178
|
+
quote_bound_value(value, c)
|
173
179
|
end
|
174
|
-
else
|
175
|
-
c.quote(value)
|
176
180
|
end
|
177
|
-
end
|
178
181
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
+
def replace_named_bind_variables(statement, bind_vars)
|
183
|
+
statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
|
184
|
+
if $1 == ":" # skip postgresql casts
|
185
|
+
match # return the whole match
|
186
|
+
elsif bind_vars.include?(match = $2.to_sym)
|
187
|
+
replace_bind_variable(bind_vars[match])
|
188
|
+
else
|
189
|
+
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
|
190
|
+
end
|
191
|
+
end
|
182
192
|
end
|
183
|
-
end
|
184
|
-
end
|
185
193
|
|
186
|
-
|
187
|
-
|
188
|
-
|
194
|
+
def quote_bound_value(value, c = connection)
|
195
|
+
if value.respond_to?(:map) && !value.acts_like?(:string)
|
196
|
+
quoted = value.map { |v| c.quote(v) }
|
197
|
+
if quoted.empty?
|
198
|
+
c.quote(nil)
|
199
|
+
else
|
200
|
+
quoted.join(",")
|
201
|
+
end
|
202
|
+
else
|
203
|
+
c.quote(value)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def raise_if_bind_arity_mismatch(statement, expected, provided)
|
208
|
+
unless expected == provided
|
209
|
+
raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
|
210
|
+
end
|
211
|
+
end
|
189
212
|
end
|
190
213
|
end
|
191
214
|
end
|
data/lib/active_record/schema.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Schema
|
4
|
+
# = Active Record \Schema
|
3
5
|
#
|
4
6
|
# Allows programmers to programmatically define a schema in a portable
|
5
7
|
# DSL. This means you can define tables, indexes, etc. without using SQL
|
@@ -27,38 +29,33 @@ module ActiveRecord
|
|
27
29
|
#
|
28
30
|
# ActiveRecord::Schema is only supported by database adapters that also
|
29
31
|
# support migrations, the two features being very similar.
|
30
|
-
class Schema < Migration
|
31
|
-
|
32
|
-
# Returns the migrations paths.
|
33
|
-
#
|
34
|
-
# ActiveRecord::Schema.new.migrations_paths
|
35
|
-
# # => ["db/migrate"] # Rails migration path by default.
|
36
|
-
def migrations_paths
|
37
|
-
ActiveRecord::Migrator.migrations_paths
|
38
|
-
end
|
39
|
-
|
40
|
-
def define(info, &block) # :nodoc:
|
41
|
-
instance_eval(&block)
|
42
|
-
|
43
|
-
unless info[:version].blank?
|
44
|
-
initialize_schema_migrations_table
|
45
|
-
connection.assume_migrated_upto_version(info[:version], migrations_paths)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
32
|
+
class Schema < Migration::Current
|
49
33
|
# Eval the given block. All methods available to the current connection
|
50
34
|
# adapter are available within the block, so you can easily use the
|
51
|
-
# database definition DSL to build up your schema (
|
52
|
-
#
|
35
|
+
# database definition DSL to build up your schema (
|
36
|
+
# {create_table}[rdoc-ref:ConnectionAdapters::SchemaStatements#create_table],
|
37
|
+
# {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index], etc.).
|
53
38
|
#
|
54
39
|
# The +info+ hash is optional, and if given is used to define metadata
|
55
40
|
# about the current schema (currently, only the schema's version):
|
56
41
|
#
|
57
|
-
# ActiveRecord::Schema.define(version:
|
42
|
+
# ActiveRecord::Schema.define(version: 2038_01_19_000001) do
|
58
43
|
# ...
|
59
44
|
# end
|
60
|
-
def self.define(info={}, &block)
|
45
|
+
def self.define(info = {}, &block)
|
61
46
|
new.define(info, &block)
|
62
47
|
end
|
48
|
+
|
49
|
+
def define(info, &block) # :nodoc:
|
50
|
+
instance_eval(&block)
|
51
|
+
|
52
|
+
if info[:version].present?
|
53
|
+
connection.schema_migration.create_table
|
54
|
+
connection.assume_migrated_upto_version(info[:version])
|
55
|
+
end
|
56
|
+
|
57
|
+
ActiveRecord::InternalMetadata.create_table
|
58
|
+
ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
|
59
|
+
end
|
63
60
|
end
|
64
61
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
# = Active Record Schema Dumper
|
@@ -12,14 +13,19 @@ module ActiveRecord
|
|
12
13
|
##
|
13
14
|
# :singleton-method:
|
14
15
|
# A list of tables which should not be dumped to the schema.
|
15
|
-
# Acceptable values are strings as well as regexp.
|
16
|
-
#
|
17
|
-
cattr_accessor :ignore_tables
|
18
|
-
|
16
|
+
# Acceptable values are strings as well as regexp if ActiveRecord::Base.schema_format == :ruby.
|
17
|
+
# Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
|
18
|
+
cattr_accessor :ignore_tables, default: []
|
19
|
+
|
20
|
+
##
|
21
|
+
# :singleton-method:
|
22
|
+
# Specify a custom regular expression matching foreign keys which name
|
23
|
+
# should not be dumped to db/schema.rb.
|
24
|
+
cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
|
19
25
|
|
20
26
|
class << self
|
21
|
-
def dump(connection=ActiveRecord::Base.connection, stream=STDOUT, config = ActiveRecord::Base)
|
22
|
-
|
27
|
+
def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
|
28
|
+
connection.create_schema_dumper(generate_options(config)).dump(stream)
|
23
29
|
stream
|
24
30
|
end
|
25
31
|
|
@@ -41,31 +47,36 @@ module ActiveRecord
|
|
41
47
|
end
|
42
48
|
|
43
49
|
private
|
50
|
+
attr_accessor :table_name
|
44
51
|
|
45
52
|
def initialize(connection, options = {})
|
46
53
|
@connection = connection
|
47
|
-
@
|
48
|
-
@version = Migrator::current_version rescue nil
|
54
|
+
@version = connection.migration_context.current_version rescue nil
|
49
55
|
@options = options
|
50
56
|
end
|
51
57
|
|
52
|
-
|
53
|
-
|
58
|
+
# turns 20170404131909 into "2017_04_04_131909"
|
59
|
+
def formatted_version
|
60
|
+
stringified = @version.to_s
|
61
|
+
return stringified unless stringified.length == 14
|
62
|
+
stringified.insert(4, "_").insert(7, "_").insert(10, "_")
|
63
|
+
end
|
54
64
|
|
55
|
-
|
56
|
-
|
57
|
-
|
65
|
+
def define_params
|
66
|
+
@version ? "version: #{formatted_version}" : ""
|
67
|
+
end
|
58
68
|
|
69
|
+
def header(stream)
|
59
70
|
stream.puts <<HEADER
|
60
71
|
# This file is auto-generated from the current state of the database. Instead
|
61
72
|
# of editing this file, please use the migrations feature of Active Record to
|
62
73
|
# incrementally modify your database, and then regenerate this schema definition.
|
63
74
|
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# from scratch.
|
68
|
-
#
|
75
|
+
# This file is the source Rails uses to define your schema when running `rails
|
76
|
+
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
77
|
+
# be faster and is potentially less error prone than running all of your
|
78
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
79
|
+
# migrations use external dependencies or application code.
|
69
80
|
#
|
70
81
|
# It's strongly recommended that you check this file into your version control system.
|
71
82
|
|
@@ -78,16 +89,8 @@ HEADER
|
|
78
89
|
stream.puts "end"
|
79
90
|
end
|
80
91
|
|
92
|
+
# extensions are only supported by PostgreSQL
|
81
93
|
def extensions(stream)
|
82
|
-
return unless @connection.supports_extensions?
|
83
|
-
extensions = @connection.extensions
|
84
|
-
if extensions.any?
|
85
|
-
stream.puts " # These are extensions that must be enabled in order to support this database"
|
86
|
-
extensions.each do |extension|
|
87
|
-
stream.puts " enable_extension #{extension.inspect}"
|
88
|
-
end
|
89
|
-
stream.puts
|
90
|
-
end
|
91
94
|
end
|
92
95
|
|
93
96
|
def tables(stream)
|
@@ -108,99 +111,72 @@ HEADER
|
|
108
111
|
def table(table, stream)
|
109
112
|
columns = @connection.columns(table)
|
110
113
|
begin
|
114
|
+
self.table_name = table
|
115
|
+
|
111
116
|
tbl = StringIO.new
|
112
117
|
|
113
118
|
# first dump primary key column
|
114
119
|
pk = @connection.primary_key(table)
|
115
120
|
|
116
121
|
tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
tbl.print ",
|
125
|
-
tbl.print %Q(, default: #{pkcol.default_function.inspect})
|
122
|
+
|
123
|
+
case pk
|
124
|
+
when String
|
125
|
+
tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
|
126
|
+
pkcol = columns.detect { |c| c.name == pk }
|
127
|
+
pkcolspec = column_spec_for_primary_key(pkcol)
|
128
|
+
if pkcolspec.present?
|
129
|
+
tbl.print ", #{format_colspec(pkcolspec)}"
|
126
130
|
end
|
131
|
+
when Array
|
132
|
+
tbl.print ", primary_key: #{pk.inspect}"
|
127
133
|
else
|
128
134
|
tbl.print ", id: false"
|
129
135
|
end
|
130
|
-
|
131
|
-
|
136
|
+
|
137
|
+
table_options = @connection.table_options(table)
|
138
|
+
if table_options.present?
|
139
|
+
tbl.print ", #{format_options(table_options)}"
|
140
|
+
end
|
141
|
+
|
142
|
+
tbl.puts ", force: :cascade do |t|"
|
132
143
|
|
133
144
|
# then dump all non-primary key columns
|
134
|
-
|
145
|
+
columns.each do |column|
|
135
146
|
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
136
147
|
next if column.name == pk
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
lengths = keys.map { |key|
|
145
|
-
column_specs.map { |spec|
|
146
|
-
spec[key] ? spec[key].length + 2 : 0
|
147
|
-
}.max
|
148
|
-
}
|
149
|
-
|
150
|
-
# the string we're going to sprintf our values against, with standardized column widths
|
151
|
-
format_string = lengths.map{ |len| "%-#{len}s" }
|
152
|
-
|
153
|
-
# find the max length for the 'type' column, which is special
|
154
|
-
type_length = column_specs.map{ |column| column[:type].length }.max
|
155
|
-
|
156
|
-
# add column type definition to our format string
|
157
|
-
format_string.unshift " t.%-#{type_length}s "
|
158
|
-
|
159
|
-
format_string *= ''
|
160
|
-
|
161
|
-
column_specs.each do |colspec|
|
162
|
-
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
163
|
-
values.unshift colspec[:type]
|
164
|
-
tbl.print((format_string % values).gsub(/,\s*$/, ''))
|
148
|
+
type, colspec = column_spec(column)
|
149
|
+
if type.is_a?(Symbol)
|
150
|
+
tbl.print " t.#{type} #{column.name.inspect}"
|
151
|
+
else
|
152
|
+
tbl.print " t.column #{column.name.inspect}, #{type.inspect}"
|
153
|
+
end
|
154
|
+
tbl.print ", #{format_colspec(colspec)}" if colspec.present?
|
165
155
|
tbl.puts
|
166
156
|
end
|
167
157
|
|
158
|
+
indexes_in_create(table, tbl)
|
159
|
+
|
168
160
|
tbl.puts " end"
|
169
161
|
tbl.puts
|
170
162
|
|
171
|
-
indexes(table, tbl)
|
172
|
-
|
173
163
|
tbl.rewind
|
174
164
|
stream.print tbl.read
|
175
165
|
rescue => e
|
176
166
|
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
177
167
|
stream.puts "# #{e.message}"
|
178
168
|
stream.puts
|
169
|
+
ensure
|
170
|
+
self.table_name = nil
|
179
171
|
end
|
180
|
-
|
181
|
-
stream
|
182
172
|
end
|
183
173
|
|
174
|
+
# Keep it for indexing materialized views
|
184
175
|
def indexes(table, stream)
|
185
176
|
if (indexes = @connection.indexes(table)).any?
|
186
177
|
add_index_statements = indexes.map do |index|
|
187
|
-
|
188
|
-
|
189
|
-
index.columns.inspect,
|
190
|
-
"name: #{index.name.inspect}",
|
191
|
-
]
|
192
|
-
statement_parts << 'unique: true' if index.unique
|
193
|
-
|
194
|
-
index_lengths = (index.lengths || []).compact
|
195
|
-
statement_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
|
196
|
-
|
197
|
-
index_orders = index.orders || {}
|
198
|
-
statement_parts << "order: #{index.orders.inspect}" if index_orders.any?
|
199
|
-
statement_parts << "where: #{index.where.inspect}" if index.where
|
200
|
-
statement_parts << "using: #{index.using.inspect}" if index.using
|
201
|
-
statement_parts << "type: #{index.type.inspect}" if index.type
|
202
|
-
|
203
|
-
" #{statement_parts.join(', ')}"
|
178
|
+
table_name = remove_prefix_and_suffix(index.table).inspect
|
179
|
+
" add_index #{([table_name] + index_parts(index)).join(', ')}"
|
204
180
|
end
|
205
181
|
|
206
182
|
stream.puts add_index_statements.sort.join("\n")
|
@@ -208,6 +184,31 @@ HEADER
|
|
208
184
|
end
|
209
185
|
end
|
210
186
|
|
187
|
+
def indexes_in_create(table, stream)
|
188
|
+
if (indexes = @connection.indexes(table)).any?
|
189
|
+
index_statements = indexes.map do |index|
|
190
|
+
" t.index #{index_parts(index).join(', ')}"
|
191
|
+
end
|
192
|
+
stream.puts index_statements.sort.join("\n")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def index_parts(index)
|
197
|
+
index_parts = [
|
198
|
+
index.columns.inspect,
|
199
|
+
"name: #{index.name.inspect}",
|
200
|
+
]
|
201
|
+
index_parts << "unique: true" if index.unique
|
202
|
+
index_parts << "length: #{format_index_parts(index.lengths)}" if index.lengths.present?
|
203
|
+
index_parts << "order: #{format_index_parts(index.orders)}" if index.orders.present?
|
204
|
+
index_parts << "opclass: #{format_index_parts(index.opclasses)}" if index.opclasses.present?
|
205
|
+
index_parts << "where: #{index.where.inspect}" if index.where
|
206
|
+
index_parts << "using: #{index.using.inspect}" if !@connection.default_index_type?(index)
|
207
|
+
index_parts << "type: #{index.type.inspect}" if index.type
|
208
|
+
index_parts << "comment: #{index.comment.inspect}" if index.comment
|
209
|
+
index_parts
|
210
|
+
end
|
211
|
+
|
211
212
|
def foreign_keys(table, stream)
|
212
213
|
if (foreign_keys = @connection.foreign_keys(table)).any?
|
213
214
|
add_foreign_key_statements = foreign_keys.map do |foreign_key|
|
@@ -224,7 +225,7 @@ HEADER
|
|
224
225
|
parts << "primary_key: #{foreign_key.primary_key.inspect}"
|
225
226
|
end
|
226
227
|
|
227
|
-
if foreign_key.
|
228
|
+
if foreign_key.export_name_on_schema_dump?
|
228
229
|
parts << "name: #{foreign_key.name.inspect}"
|
229
230
|
end
|
230
231
|
|
@@ -238,12 +239,30 @@ HEADER
|
|
238
239
|
end
|
239
240
|
end
|
240
241
|
|
242
|
+
def format_colspec(colspec)
|
243
|
+
colspec.map { |key, value| "#{key}: #{value}" }.join(", ")
|
244
|
+
end
|
245
|
+
|
246
|
+
def format_options(options)
|
247
|
+
options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
|
248
|
+
end
|
249
|
+
|
250
|
+
def format_index_parts(options)
|
251
|
+
if options.is_a?(Hash)
|
252
|
+
"{ #{format_options(options)} }"
|
253
|
+
else
|
254
|
+
options.inspect
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
241
258
|
def remove_prefix_and_suffix(table)
|
242
|
-
|
259
|
+
prefix = Regexp.escape(@options[:table_name_prefix].to_s)
|
260
|
+
suffix = Regexp.escape(@options[:table_name_suffix].to_s)
|
261
|
+
table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
|
243
262
|
end
|
244
263
|
|
245
264
|
def ignored?(table_name)
|
246
|
-
[
|
265
|
+
[ActiveRecord::Base.schema_migrations_table_name, ActiveRecord::Base.internal_metadata_table_name, ignore_tables].flatten.any? do |ignored|
|
247
266
|
ignored === remove_prefix_and_suffix(table_name)
|
248
267
|
end
|
249
268
|
end
|