omg-activerecord 8.0.0.alpha1
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 +7 -0
- data/CHANGELOG.md +355 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +219 -0
- data/examples/performance.rb +185 -0
- data/examples/simple.rb +15 -0
- data/lib/active_record/aggregations.rb +287 -0
- data/lib/active_record/association_relation.rb +50 -0
- data/lib/active_record/associations/alias_tracker.rb +90 -0
- data/lib/active_record/associations/association.rb +417 -0
- data/lib/active_record/associations/association_scope.rb +175 -0
- data/lib/active_record/associations/belongs_to_association.rb +163 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/builder/association.rb +170 -0
- data/lib/active_record/associations/builder/belongs_to.rb +160 -0
- data/lib/active_record/associations/builder/collection_association.rb +80 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
- data/lib/active_record/associations/builder/has_many.rb +23 -0
- data/lib/active_record/associations/builder/has_one.rb +61 -0
- data/lib/active_record/associations/builder/singular_association.rb +48 -0
- data/lib/active_record/associations/collection_association.rb +535 -0
- data/lib/active_record/associations/collection_proxy.rb +1163 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +40 -0
- data/lib/active_record/associations/has_many_association.rb +167 -0
- data/lib/active_record/associations/has_many_through_association.rb +232 -0
- data/lib/active_record/associations/has_one_association.rb +142 -0
- data/lib/active_record/associations/has_one_through_association.rb +45 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/join_dependency.rb +301 -0
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +316 -0
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +150 -0
- data/lib/active_record/associations/preloader.rb +135 -0
- data/lib/active_record/associations/singular_association.rb +76 -0
- data/lib/active_record/associations/through_association.rb +132 -0
- data/lib/active_record/associations.rb +1897 -0
- data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
- data/lib/active_record/attribute_assignment.rb +82 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +262 -0
- data/lib/active_record/attribute_methods/primary_key.rb +158 -0
- data/lib/active_record/attribute_methods/query.rb +50 -0
- data/lib/active_record/attribute_methods/read.rb +46 -0
- data/lib/active_record/attribute_methods/serialization.rb +232 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
- data/lib/active_record/attribute_methods/write.rb +49 -0
- data/lib/active_record/attribute_methods.rb +542 -0
- data/lib/active_record/attributes.rb +307 -0
- data/lib/active_record/autosave_association.rb +586 -0
- data/lib/active_record/base.rb +338 -0
- data/lib/active_record/callbacks.rb +452 -0
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
- data/lib/active_record/connection_adapters/column.rb +122 -0
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
- data/lib/active_record/connection_adapters.rb +176 -0
- data/lib/active_record/connection_handling.rb +413 -0
- data/lib/active_record/core.rb +836 -0
- data/lib/active_record/counter_cache.rb +230 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
- data/lib/active_record/database_configurations/database_config.rb +104 -0
- data/lib/active_record/database_configurations/hash_config.rb +172 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +309 -0
- data/lib/active_record/delegated_type.rb +289 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +121 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +70 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +177 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +107 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +424 -0
- data/lib/active_record/errors.rb +614 -0
- data/lib/active_record/explain.rb +63 -0
- data/lib/active_record/explain_registry.rb +37 -0
- data/lib/active_record/explain_subscriber.rb +34 -0
- data/lib/active_record/fixture_set/file.rb +89 -0
- data/lib/active_record/fixture_set/model_metadata.rb +42 -0
- data/lib/active_record/fixture_set/render_context.rb +19 -0
- data/lib/active_record/fixture_set/table_row.rb +208 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +850 -0
- data/lib/active_record/future_result.rb +182 -0
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +366 -0
- data/lib/active_record/insert_all.rb +328 -0
- data/lib/active_record/integration.rb +209 -0
- data/lib/active_record/internal_metadata.rb +164 -0
- data/lib/active_record/legacy_yaml_adapter.rb +15 -0
- data/lib/active_record/locale/en.yml +48 -0
- data/lib/active_record/locking/optimistic.rb +228 -0
- data/lib/active_record/locking/pessimistic.rb +102 -0
- data/lib/active_record/log_subscriber.rb +149 -0
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +87 -0
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +406 -0
- data/lib/active_record/migration/compatibility.rb +490 -0
- 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/join_table.rb +16 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +1626 -0
- data/lib/active_record/model_schema.rb +635 -0
- data/lib/active_record/nested_attributes.rb +633 -0
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +968 -0
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +56 -0
- data/lib/active_record/query_logs.rb +247 -0
- data/lib/active_record/query_logs_formatter.rb +30 -0
- data/lib/active_record/querying.rb +122 -0
- data/lib/active_record/railtie.rb +440 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +65 -0
- data/lib/active_record/railties/databases.rake +641 -0
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +66 -0
- data/lib/active_record/reflection.rb +1287 -0
- data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
- data/lib/active_record/relation/batches.rb +491 -0
- data/lib/active_record/relation/calculations.rb +679 -0
- data/lib/active_record/relation/delegation.rb +154 -0
- data/lib/active_record/relation/finder_methods.rb +661 -0
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +192 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -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 +60 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
- data/lib/active_record/relation/predicate_builder.rb +181 -0
- data/lib/active_record/relation/query_attribute.rb +68 -0
- data/lib/active_record/relation/query_methods.rb +2235 -0
- data/lib/active_record/relation/record_fetch_warning.rb +52 -0
- data/lib/active_record/relation/spawn_methods.rb +78 -0
- data/lib/active_record/relation/where_clause.rb +218 -0
- data/lib/active_record/relation.rb +1495 -0
- data/lib/active_record/result.rb +249 -0
- data/lib/active_record/runtime_registry.rb +82 -0
- data/lib/active_record/sanitization.rb +254 -0
- data/lib/active_record/schema.rb +77 -0
- data/lib/active_record/schema_dumper.rb +364 -0
- data/lib/active_record/schema_migration.rb +106 -0
- data/lib/active_record/scoping/default.rb +205 -0
- data/lib/active_record/scoping/named.rb +202 -0
- data/lib/active_record/scoping.rb +136 -0
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +66 -0
- data/lib/active_record/serialization.rb +29 -0
- data/lib/active_record/signed_id.rb +137 -0
- data/lib/active_record/statement_cache.rb +164 -0
- data/lib/active_record/store.rb +299 -0
- data/lib/active_record/suppressor.rb +59 -0
- data/lib/active_record/table_metadata.rb +85 -0
- data/lib/active_record/tasks/database_tasks.rb +681 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +321 -0
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +177 -0
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +70 -0
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +523 -0
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/type/adapter_specific_registry.rb +144 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
- data/lib/active_record/type/internal/timezone.rb +22 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +76 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +35 -0
- data/lib/active_record/type/type_map.rb +58 -0
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type.rb +83 -0
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +65 -0
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +45 -0
- data/lib/active_record/validations/uniqueness.rb +295 -0
- data/lib/active_record/validations.rb +101 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/active_record.rb +616 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +33 -0
- data/lib/arel/collectors/bind.rb +31 -0
- data/lib/arel/collectors/composite.rb +46 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +48 -0
- data/lib/arel/delete_manager.rb +32 -0
- data/lib/arel/errors.rb +19 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +53 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +48 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +125 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +44 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +45 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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/leading_join.rb +8 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/nary.rb +39 -0
- data/lib/arel/nodes/node.rb +161 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +32 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +35 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -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 +46 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +75 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +260 -0
- data/lib/arel/select_manager.rb +276 -0
- data/lib/arel/table.rb +121 -0
- data/lib/arel/tree_manager.rb +65 -0
- data/lib/arel/update_manager.rb +49 -0
- data/lib/arel/visitors/dot.rb +299 -0
- data/lib/arel/visitors/mysql.rb +111 -0
- data/lib/arel/visitors/postgresql.rb +99 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +1033 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +73 -0
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +76 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
- data/lib/rails/generators/active_record/migration.rb +54 -0
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- data/lib/rails/generators/active_record.rb +19 -0
- metadata +505 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
module DatabaseStatements
|
|
7
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
8
|
+
:pragma
|
|
9
|
+
) # :nodoc:
|
|
10
|
+
private_constant :READ_QUERY
|
|
11
|
+
|
|
12
|
+
def write_query?(sql) # :nodoc:
|
|
13
|
+
!READ_QUERY.match?(sql)
|
|
14
|
+
rescue ArgumentError # Invalid encoding
|
|
15
|
+
!READ_QUERY.match?(sql.b)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def explain(arel, binds = [], _options = [])
|
|
19
|
+
sql = "EXPLAIN QUERY PLAN " + to_sql(arel, binds)
|
|
20
|
+
result = internal_exec_query(sql, "EXPLAIN", [])
|
|
21
|
+
SQLite3::ExplainPrettyPrinter.new.pp(result)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def begin_deferred_transaction(isolation = nil) # :nodoc:
|
|
25
|
+
internal_begin_transaction(:deferred, isolation)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
29
|
+
internal_begin_transaction(:deferred, isolation)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def begin_db_transaction # :nodoc:
|
|
33
|
+
internal_begin_transaction(:immediate, nil)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def commit_db_transaction # :nodoc:
|
|
37
|
+
internal_execute("COMMIT TRANSACTION", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def exec_rollback_db_transaction # :nodoc:
|
|
41
|
+
internal_execute("ROLLBACK TRANSACTION", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# https://stackoverflow.com/questions/17574784
|
|
45
|
+
# https://www.sqlite.org/lang_datefunc.html
|
|
46
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')", retryable: true).freeze # :nodoc:
|
|
47
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
|
48
|
+
|
|
49
|
+
def high_precision_current_timestamp
|
|
50
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def execute(...) # :nodoc:
|
|
54
|
+
# SQLite3Adapter was refactored to use ActiveRecord::Result internally
|
|
55
|
+
# but for backward compatibility we have to keep returning arrays of hashes here
|
|
56
|
+
super&.to_a
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def reset_isolation_level # :nodoc:
|
|
60
|
+
internal_execute("PRAGMA read_uncommitted=#{@previous_read_uncommitted}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
61
|
+
@previous_read_uncommitted = nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
def internal_begin_transaction(mode, isolation)
|
|
66
|
+
if isolation
|
|
67
|
+
raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
|
|
68
|
+
raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
internal_execute("BEGIN #{mode} TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
72
|
+
if isolation
|
|
73
|
+
@previous_read_uncommitted = query_value("PRAGMA read_uncommitted")
|
|
74
|
+
internal_execute("PRAGMA read_uncommitted=ON", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
79
|
+
if batch
|
|
80
|
+
raw_connection.execute_batch2(sql)
|
|
81
|
+
elsif prepare
|
|
82
|
+
stmt = @statements[sql] ||= raw_connection.prepare(sql)
|
|
83
|
+
stmt.reset!
|
|
84
|
+
stmt.bind_params(type_casted_binds)
|
|
85
|
+
|
|
86
|
+
result = if stmt.column_count.zero? # No return
|
|
87
|
+
stmt.step
|
|
88
|
+
ActiveRecord::Result.empty
|
|
89
|
+
else
|
|
90
|
+
ActiveRecord::Result.new(stmt.columns, stmt.to_a)
|
|
91
|
+
end
|
|
92
|
+
else
|
|
93
|
+
# Don't cache statements if they are not prepared.
|
|
94
|
+
stmt = raw_connection.prepare(sql)
|
|
95
|
+
begin
|
|
96
|
+
unless binds.nil? || binds.empty?
|
|
97
|
+
stmt.bind_params(type_casted_binds)
|
|
98
|
+
end
|
|
99
|
+
result = if stmt.column_count.zero? # No return
|
|
100
|
+
stmt.step
|
|
101
|
+
ActiveRecord::Result.empty
|
|
102
|
+
else
|
|
103
|
+
ActiveRecord::Result.new(stmt.columns, stmt.to_a)
|
|
104
|
+
end
|
|
105
|
+
ensure
|
|
106
|
+
stmt.close
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
@last_affected_rows = raw_connection.changes
|
|
110
|
+
verified!
|
|
111
|
+
|
|
112
|
+
notification_payload[:row_count] = result&.length || 0
|
|
113
|
+
result
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def cast_result(result)
|
|
117
|
+
# Given that SQLite3 doesn't really a Result type, raw_execute already return an ActiveRecord::Result
|
|
118
|
+
# and we have nothing to cast here.
|
|
119
|
+
result
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def affected_rows(result)
|
|
123
|
+
@last_affected_rows
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def execute_batch(statements, name = nil, **kwargs)
|
|
127
|
+
sql = combine_multi_statements(statements)
|
|
128
|
+
raw_execute(sql, name, batch: true, **kwargs)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def build_truncate_statement(table_name)
|
|
132
|
+
"DELETE FROM #{quote_table_name(table_name)}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def returning_column_values(result)
|
|
136
|
+
result.rows.first
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def default_insert_value(column)
|
|
140
|
+
column.default
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
class ExplainPrettyPrinter # :nodoc:
|
|
7
|
+
# Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles
|
|
8
|
+
# the output of the SQLite shell:
|
|
9
|
+
#
|
|
10
|
+
# 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
|
|
11
|
+
# 0|1|1|SCAN TABLE posts (~100000 rows)
|
|
12
|
+
#
|
|
13
|
+
def pp(result)
|
|
14
|
+
result.rows.map do |row|
|
|
15
|
+
row.join("|")
|
|
16
|
+
end.join("\n") + "\n"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
module Quoting # :nodoc:
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
|
10
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
|
11
|
+
|
|
12
|
+
module ClassMethods # :nodoc:
|
|
13
|
+
def column_name_matcher
|
|
14
|
+
/
|
|
15
|
+
\A
|
|
16
|
+
(
|
|
17
|
+
(?:
|
|
18
|
+
# "table_name"."column_name" | function(one or no argument)
|
|
19
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
|
20
|
+
)
|
|
21
|
+
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
|
22
|
+
)
|
|
23
|
+
(?:\s*,\s*\g<1>)*
|
|
24
|
+
\z
|
|
25
|
+
/ix
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def column_name_with_order_matcher
|
|
29
|
+
/
|
|
30
|
+
\A
|
|
31
|
+
(
|
|
32
|
+
(?:
|
|
33
|
+
# "table_name"."column_name" | function(one or no argument)
|
|
34
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
|
35
|
+
)
|
|
36
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
|
37
|
+
(?:\s+ASC|\s+DESC)?
|
|
38
|
+
)
|
|
39
|
+
(?:\s*,\s*\g<1>)*
|
|
40
|
+
\z
|
|
41
|
+
/ix
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def quote_column_name(name)
|
|
45
|
+
QUOTED_COLUMN_NAMES[name] ||= %Q("#{name.to_s.gsub('"', '""')}").freeze
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def quote_table_name(name)
|
|
49
|
+
QUOTED_TABLE_NAMES[name] ||= %Q("#{name.to_s.gsub('"', '""').gsub(".", "\".\"")}").freeze
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def quote_string(s)
|
|
54
|
+
::SQLite3::Database.quote(s)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def quote_table_name_for_assignment(table, attr)
|
|
58
|
+
quote_column_name(attr)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def quoted_time(value)
|
|
62
|
+
value = value.change(year: 2000, month: 1, day: 1)
|
|
63
|
+
quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def quoted_binary(value)
|
|
67
|
+
"x'#{value.hex}'"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def quoted_true
|
|
71
|
+
"1"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def unquoted_true
|
|
75
|
+
1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def quoted_false
|
|
79
|
+
"0"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def unquoted_false
|
|
83
|
+
0
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def quote_default_expression(value, column) # :nodoc:
|
|
87
|
+
if value.is_a?(Proc)
|
|
88
|
+
value = value.call
|
|
89
|
+
if value.match?(/\A\w+\(.*\)\z/)
|
|
90
|
+
"(#{value})"
|
|
91
|
+
else
|
|
92
|
+
value
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
super
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def type_cast(value) # :nodoc:
|
|
100
|
+
case value
|
|
101
|
+
when BigDecimal, Rational
|
|
102
|
+
value.to_f
|
|
103
|
+
when String
|
|
104
|
+
if value.encoding == Encoding::ASCII_8BIT
|
|
105
|
+
super(value.encode(Encoding::UTF_8))
|
|
106
|
+
else
|
|
107
|
+
super
|
|
108
|
+
end
|
|
109
|
+
else
|
|
110
|
+
super
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
class SchemaCreation < SchemaCreation # :nodoc:
|
|
7
|
+
private
|
|
8
|
+
def visit_ForeignKeyDefinition(o)
|
|
9
|
+
super.dup.tap do |sql|
|
|
10
|
+
sql << " DEFERRABLE INITIALLY #{o.deferrable.to_s.upcase}" if o.deferrable
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def supports_index_using?
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_column_options!(sql, options)
|
|
19
|
+
if options[:collation]
|
|
20
|
+
sql << " COLLATE \"#{options[:collation]}\""
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if as = options[:as]
|
|
24
|
+
sql << " GENERATED ALWAYS AS (#{as})"
|
|
25
|
+
|
|
26
|
+
if options[:stored]
|
|
27
|
+
sql << " STORED"
|
|
28
|
+
else
|
|
29
|
+
sql << " VIRTUAL"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
# = Active Record SQLite3 Adapter \Table Definition
|
|
7
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
|
8
|
+
def change_column(column_name, type, **options)
|
|
9
|
+
name = column_name.to_s
|
|
10
|
+
@columns_hash[name] = nil
|
|
11
|
+
column(name, type, **options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def references(*args, **options)
|
|
15
|
+
super(*args, type: :integer, **options)
|
|
16
|
+
end
|
|
17
|
+
alias :belongs_to :references
|
|
18
|
+
|
|
19
|
+
def new_column_definition(name, type, **options) # :nodoc:
|
|
20
|
+
case type
|
|
21
|
+
when :virtual
|
|
22
|
+
type = options[:type]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
def integer_like_primary_key_type(type, options)
|
|
30
|
+
:primary_key
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def valid_column_definition_options
|
|
34
|
+
super + [:as, :type, :stored]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
|
|
7
|
+
private
|
|
8
|
+
def virtual_tables(stream)
|
|
9
|
+
virtual_tables = @connection.virtual_tables
|
|
10
|
+
if virtual_tables.any?
|
|
11
|
+
stream.puts
|
|
12
|
+
stream.puts " # Virtual tables defined in this database."
|
|
13
|
+
stream.puts " # Note that virtual tables may not work with other database engines. Be careful if changing database."
|
|
14
|
+
virtual_tables.sort.each do |table_name, options|
|
|
15
|
+
module_name, arguments = options
|
|
16
|
+
stream.puts " create_virtual_table #{table_name.inspect}, #{module_name.inspect}, #{arguments.split(", ").inspect}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def default_primary_key?(column)
|
|
22
|
+
schema_type(column) == :integer
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def explicit_primary_key_default?(column)
|
|
26
|
+
column.bigint?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def prepare_column_options(column)
|
|
30
|
+
spec = super
|
|
31
|
+
|
|
32
|
+
if @connection.supports_virtual_columns? && column.virtual?
|
|
33
|
+
spec[:as] = extract_expression_for_virtual_column(column)
|
|
34
|
+
spec[:stored] = column.virtual_stored?
|
|
35
|
+
spec = { type: schema_type(column).inspect }.merge!(spec)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
spec
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def extract_expression_for_virtual_column(column)
|
|
42
|
+
column.default_function.inspect
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module ConnectionAdapters
|
|
5
|
+
module SQLite3
|
|
6
|
+
module SchemaStatements # :nodoc:
|
|
7
|
+
# Returns an array of indexes for the given table.
|
|
8
|
+
def indexes(table_name)
|
|
9
|
+
internal_exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").filter_map do |row|
|
|
10
|
+
# Indexes SQLite creates implicitly for internal use start with "sqlite_".
|
|
11
|
+
# See https://www.sqlite.org/fileformat2.html#intschema
|
|
12
|
+
next if row["name"].start_with?("sqlite_")
|
|
13
|
+
|
|
14
|
+
index_sql = query_value(<<~SQL, "SCHEMA")
|
|
15
|
+
SELECT sql
|
|
16
|
+
FROM sqlite_master
|
|
17
|
+
WHERE name = #{quote(row['name'])} AND type = 'index'
|
|
18
|
+
UNION ALL
|
|
19
|
+
SELECT sql
|
|
20
|
+
FROM sqlite_temp_master
|
|
21
|
+
WHERE name = #{quote(row['name'])} AND type = 'index'
|
|
22
|
+
SQL
|
|
23
|
+
|
|
24
|
+
/\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?(?:\s*\/\*.*\*\/)?\z/i =~ index_sql
|
|
25
|
+
|
|
26
|
+
columns = internal_exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
|
|
27
|
+
col["name"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
orders = {}
|
|
31
|
+
|
|
32
|
+
if columns.any?(&:nil?) # index created with an expression
|
|
33
|
+
columns = expressions
|
|
34
|
+
else
|
|
35
|
+
# Add info on sort order for columns (only desc order is explicitly specified,
|
|
36
|
+
# asc is the default)
|
|
37
|
+
if index_sql # index_sql can be null in case of primary key indexes
|
|
38
|
+
index_sql.scan(/"(\w+)" DESC/).flatten.each { |order_column|
|
|
39
|
+
orders[order_column] = :desc
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
IndexDefinition.new(
|
|
45
|
+
table_name,
|
|
46
|
+
row["name"],
|
|
47
|
+
row["unique"] != 0,
|
|
48
|
+
columns,
|
|
49
|
+
where: where,
|
|
50
|
+
orders: orders
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def add_foreign_key(from_table, to_table, **options)
|
|
56
|
+
assert_valid_deferrable(options[:deferrable])
|
|
57
|
+
|
|
58
|
+
alter_table(from_table) do |definition|
|
|
59
|
+
to_table = strip_table_name_prefix_and_suffix(to_table)
|
|
60
|
+
definition.foreign_key(to_table, **options)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def remove_foreign_key(from_table, to_table = nil, **options)
|
|
65
|
+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
|
|
66
|
+
|
|
67
|
+
to_table ||= options[:to_table]
|
|
68
|
+
options = options.except(:name, :to_table, :validate)
|
|
69
|
+
foreign_keys = foreign_keys(from_table)
|
|
70
|
+
|
|
71
|
+
fkey = foreign_keys.detect do |fk|
|
|
72
|
+
table = to_table || begin
|
|
73
|
+
table = options[:column].to_s.delete_suffix("_id")
|
|
74
|
+
Base.pluralize_table_names ? table.pluralize : table
|
|
75
|
+
end
|
|
76
|
+
table = strip_table_name_prefix_and_suffix(table)
|
|
77
|
+
fk_to_table = strip_table_name_prefix_and_suffix(fk.to_table)
|
|
78
|
+
fk_to_table == table && options.all? { |k, v| fk.options[k].to_s == v.to_s }
|
|
79
|
+
end || raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
|
|
80
|
+
|
|
81
|
+
foreign_keys.delete(fkey)
|
|
82
|
+
alter_table(from_table, foreign_keys)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def virtual_table_exists?(table_name)
|
|
86
|
+
query_values(data_source_sql(table_name, type: "VIRTUAL TABLE"), "SCHEMA").any?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def check_constraints(table_name)
|
|
90
|
+
table_sql = query_value(<<-SQL, "SCHEMA")
|
|
91
|
+
SELECT sql
|
|
92
|
+
FROM sqlite_master
|
|
93
|
+
WHERE name = #{quote(table_name)} AND type = 'table'
|
|
94
|
+
UNION ALL
|
|
95
|
+
SELECT sql
|
|
96
|
+
FROM sqlite_temp_master
|
|
97
|
+
WHERE name = #{quote(table_name)} AND type = 'table'
|
|
98
|
+
SQL
|
|
99
|
+
|
|
100
|
+
table_sql.to_s.scan(/CONSTRAINT\s+(?<name>\w+)\s+CHECK\s+\((?<expression>(:?[^()]|\(\g<expression>\))+)\)/i).map do |name, expression|
|
|
101
|
+
CheckConstraintDefinition.new(table_name, expression, name: name)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def add_check_constraint(table_name, expression, **options)
|
|
106
|
+
alter_table(table_name) do |definition|
|
|
107
|
+
definition.check_constraint(expression, **options)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def remove_check_constraint(table_name, expression = nil, if_exists: false, **options)
|
|
112
|
+
return if if_exists && !check_constraint_exists?(table_name, **options)
|
|
113
|
+
|
|
114
|
+
check_constraints = check_constraints(table_name)
|
|
115
|
+
chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
|
|
116
|
+
check_constraints.delete_if { |chk| chk.name == chk_name_to_delete }
|
|
117
|
+
alter_table(table_name, foreign_keys(table_name), check_constraints)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def create_schema_dumper(options)
|
|
121
|
+
SQLite3::SchemaDumper.create(self, options)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def schema_creation # :nodoc
|
|
125
|
+
SQLite3::SchemaCreation.new(self)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
def valid_table_definition_options
|
|
130
|
+
super + [:rename]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def create_table_definition(name, **options)
|
|
134
|
+
SQLite3::TableDefinition.new(self, name, **options)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def validate_index_length!(table_name, new_name, internal = false)
|
|
138
|
+
super unless internal
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def new_column_from_field(table_name, field, definitions)
|
|
142
|
+
default = field["dflt_value"]
|
|
143
|
+
|
|
144
|
+
type_metadata = fetch_type_metadata(field["type"])
|
|
145
|
+
default_value = extract_value_from_default(default)
|
|
146
|
+
generated_type = extract_generated_type(field)
|
|
147
|
+
|
|
148
|
+
if generated_type.present?
|
|
149
|
+
default_function = default
|
|
150
|
+
else
|
|
151
|
+
default_function = extract_default_function(default_value, default)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
rowid = is_column_the_rowid?(field, definitions)
|
|
155
|
+
|
|
156
|
+
Column.new(
|
|
157
|
+
field["name"],
|
|
158
|
+
default_value,
|
|
159
|
+
type_metadata,
|
|
160
|
+
field["notnull"].to_i == 0,
|
|
161
|
+
default_function,
|
|
162
|
+
collation: field["collation"],
|
|
163
|
+
auto_increment: field["auto_increment"],
|
|
164
|
+
rowid: rowid,
|
|
165
|
+
generated_type: generated_type
|
|
166
|
+
)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
INTEGER_REGEX = /integer/i
|
|
170
|
+
# if a rowid table has a primary key that consists of a single column
|
|
171
|
+
# and the declared type of that column is "INTEGER" in any mixture of upper and lower case,
|
|
172
|
+
# then the column becomes an alias for the rowid.
|
|
173
|
+
def is_column_the_rowid?(field, column_definitions)
|
|
174
|
+
return false unless INTEGER_REGEX.match?(field["type"]) && field["pk"] == 1
|
|
175
|
+
# is the primary key a single column?
|
|
176
|
+
column_definitions.one? { |c| c["pk"] > 0 }
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def data_source_sql(name = nil, type: nil)
|
|
180
|
+
scope = quoted_scope(name, type: type)
|
|
181
|
+
scope[:type] ||= "'table','view'"
|
|
182
|
+
|
|
183
|
+
sql = +"SELECT name FROM pragma_table_list WHERE schema <> 'temp'"
|
|
184
|
+
sql << " AND name NOT IN ('sqlite_sequence', 'sqlite_schema')"
|
|
185
|
+
sql << " AND name = #{scope[:name]}" if scope[:name]
|
|
186
|
+
sql << " AND type IN (#{scope[:type]})"
|
|
187
|
+
sql
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def quoted_scope(name = nil, type: nil)
|
|
191
|
+
type = \
|
|
192
|
+
case type
|
|
193
|
+
when "BASE TABLE"
|
|
194
|
+
"'table'"
|
|
195
|
+
when "VIEW"
|
|
196
|
+
"'view'"
|
|
197
|
+
when "VIRTUAL TABLE"
|
|
198
|
+
"'virtual'"
|
|
199
|
+
end
|
|
200
|
+
scope = {}
|
|
201
|
+
scope[:name] = quote(name) if name
|
|
202
|
+
scope[:type] = type if type
|
|
203
|
+
scope
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def assert_valid_deferrable(deferrable)
|
|
207
|
+
return if !deferrable || %i(immediate deferred).include?(deferrable)
|
|
208
|
+
|
|
209
|
+
raise ArgumentError, "deferrable must be `:immediate` or `:deferred`, got: `#{deferrable.inspect}`"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def extract_generated_type(field)
|
|
213
|
+
case field["hidden"]
|
|
214
|
+
when 2 then :virtual
|
|
215
|
+
when 3 then :stored
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|