sequel 4.26.0 → 5.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG +405 -5656
- data/MIT-LICENSE +1 -1
- data/README.rdoc +232 -157
- data/bin/sequel +32 -9
- data/doc/advanced_associations.rdoc +252 -188
- data/doc/association_basics.rdoc +231 -273
- data/doc/bin_sequel.rdoc +5 -3
- data/doc/cheat_sheet.rdoc +75 -48
- data/doc/code_order.rdoc +28 -10
- data/doc/core_extensions.rdoc +104 -63
- data/doc/dataset_basics.rdoc +12 -21
- data/doc/dataset_filtering.rdoc +99 -86
- data/doc/extensions.rdoc +3 -10
- data/doc/mass_assignment.rdoc +74 -31
- data/doc/migration.rdoc +72 -46
- data/doc/model_dataset_method_design.rdoc +129 -0
- data/doc/model_hooks.rdoc +15 -25
- data/doc/model_plugins.rdoc +12 -12
- data/doc/mssql_stored_procedures.rdoc +3 -3
- data/doc/object_model.rdoc +59 -69
- data/doc/opening_databases.rdoc +84 -94
- data/doc/postgresql.rdoc +268 -38
- data/doc/prepared_statements.rdoc +29 -24
- data/doc/querying.rdoc +184 -164
- data/doc/reflection.rdoc +5 -6
- data/doc/release_notes/5.0.0.txt +159 -0
- data/doc/release_notes/5.1.0.txt +31 -0
- data/doc/release_notes/5.10.0.txt +84 -0
- data/doc/release_notes/5.11.0.txt +83 -0
- data/doc/release_notes/5.12.0.txt +141 -0
- data/doc/release_notes/5.13.0.txt +27 -0
- data/doc/release_notes/5.14.0.txt +63 -0
- data/doc/release_notes/5.15.0.txt +39 -0
- data/doc/release_notes/5.16.0.txt +110 -0
- data/doc/release_notes/5.17.0.txt +31 -0
- data/doc/release_notes/5.18.0.txt +69 -0
- data/doc/release_notes/5.19.0.txt +28 -0
- data/doc/release_notes/5.2.0.txt +33 -0
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/release_notes/5.25.0.txt +32 -0
- data/doc/release_notes/5.26.0.txt +35 -0
- data/doc/release_notes/5.27.0.txt +21 -0
- data/doc/release_notes/5.28.0.txt +16 -0
- data/doc/release_notes/5.29.0.txt +22 -0
- data/doc/release_notes/5.3.0.txt +121 -0
- data/doc/release_notes/5.30.0.txt +20 -0
- data/doc/release_notes/5.31.0.txt +148 -0
- data/doc/release_notes/5.32.0.txt +46 -0
- data/doc/release_notes/5.33.0.txt +24 -0
- data/doc/release_notes/5.34.0.txt +40 -0
- data/doc/release_notes/5.35.0.txt +56 -0
- data/doc/release_notes/5.36.0.txt +60 -0
- data/doc/release_notes/5.37.0.txt +30 -0
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/release_notes/5.5.0.txt +61 -0
- data/doc/release_notes/5.6.0.txt +31 -0
- data/doc/release_notes/5.7.0.txt +108 -0
- data/doc/release_notes/5.8.0.txt +170 -0
- data/doc/release_notes/5.9.0.txt +99 -0
- data/doc/schema_modification.rdoc +102 -77
- data/doc/security.rdoc +160 -87
- data/doc/sharding.rdoc +74 -47
- data/doc/sql.rdoc +135 -122
- data/doc/testing.rdoc +34 -18
- data/doc/thread_safety.rdoc +2 -4
- data/doc/transactions.rdoc +101 -19
- data/doc/validations.rdoc +64 -51
- data/doc/virtual_rows.rdoc +90 -109
- data/lib/sequel.rb +3 -1
- data/lib/sequel/adapters/ado.rb +154 -22
- data/lib/sequel/adapters/ado/access.rb +21 -21
- data/lib/sequel/adapters/ado/mssql.rb +8 -15
- data/lib/sequel/adapters/amalgalite.rb +17 -25
- data/lib/sequel/adapters/ibmdb.rb +52 -58
- data/lib/sequel/adapters/jdbc.rb +149 -127
- data/lib/sequel/adapters/jdbc/db2.rb +32 -40
- data/lib/sequel/adapters/jdbc/derby.rb +56 -58
- data/lib/sequel/adapters/jdbc/h2.rb +40 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +22 -33
- data/lib/sequel/adapters/jdbc/jtds.rb +4 -10
- data/lib/sequel/adapters/jdbc/mssql.rb +6 -12
- data/lib/sequel/adapters/jdbc/mysql.rb +17 -18
- data/lib/sequel/adapters/jdbc/oracle.rb +25 -19
- data/lib/sequel/adapters/jdbc/postgresql.rb +90 -69
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +14 -24
- data/lib/sequel/adapters/jdbc/sqlite.rb +50 -12
- data/lib/sequel/adapters/jdbc/sqlserver.rb +36 -9
- data/lib/sequel/adapters/jdbc/transactions.rb +25 -39
- data/lib/sequel/adapters/mock.rb +104 -113
- data/lib/sequel/adapters/mysql.rb +42 -61
- data/lib/sequel/adapters/mysql2.rb +126 -35
- data/lib/sequel/adapters/odbc.rb +21 -28
- data/lib/sequel/adapters/odbc/db2.rb +3 -1
- data/lib/sequel/adapters/odbc/mssql.rb +11 -15
- data/lib/sequel/adapters/odbc/oracle.rb +11 -0
- data/lib/sequel/adapters/oracle.rb +62 -68
- data/lib/sequel/adapters/postgres.rb +257 -311
- data/lib/sequel/adapters/postgresql.rb +3 -1
- data/lib/sequel/adapters/shared/access.rb +75 -79
- data/lib/sequel/adapters/shared/db2.rb +96 -74
- data/lib/sequel/adapters/shared/mssql.rb +258 -213
- data/lib/sequel/adapters/shared/mysql.rb +284 -216
- data/lib/sequel/adapters/shared/oracle.rb +175 -60
- data/lib/sequel/adapters/shared/postgres.rb +829 -383
- data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -127
- data/lib/sequel/adapters/shared/sqlite.rb +382 -159
- data/lib/sequel/adapters/sqlanywhere.rb +53 -38
- data/lib/sequel/adapters/sqlite.rb +111 -105
- data/lib/sequel/adapters/tinytds.rb +38 -46
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -9
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -5
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
- data/lib/sequel/adapters/utils/replace.rb +3 -4
- data/lib/sequel/adapters/utils/split_alter_table.rb +2 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
- data/lib/sequel/ast_transformer.rb +13 -89
- data/lib/sequel/connection_pool.rb +54 -26
- data/lib/sequel/connection_pool/sharded_single.rb +19 -12
- data/lib/sequel/connection_pool/sharded_threaded.rb +160 -111
- data/lib/sequel/connection_pool/single.rb +21 -12
- data/lib/sequel/connection_pool/threaded.rb +137 -119
- data/lib/sequel/core.rb +352 -320
- data/lib/sequel/database.rb +19 -2
- data/lib/sequel/database/connecting.rb +70 -55
- data/lib/sequel/database/dataset.rb +15 -5
- data/lib/sequel/database/dataset_defaults.rb +20 -102
- data/lib/sequel/database/features.rb +20 -4
- data/lib/sequel/database/logging.rb +25 -7
- data/lib/sequel/database/misc.rb +132 -118
- data/lib/sequel/database/query.rb +51 -28
- data/lib/sequel/database/schema_generator.rb +188 -75
- data/lib/sequel/database/schema_methods.rb +161 -92
- data/lib/sequel/database/transactions.rb +260 -58
- data/lib/sequel/dataset.rb +28 -12
- data/lib/sequel/dataset/actions.rb +354 -170
- data/lib/sequel/dataset/dataset_module.rb +46 -0
- data/lib/sequel/dataset/features.rb +81 -34
- data/lib/sequel/dataset/graph.rb +82 -58
- data/lib/sequel/dataset/misc.rb +139 -47
- data/lib/sequel/dataset/placeholder_literalizer.rb +66 -26
- data/lib/sequel/dataset/prepared_statements.rb +188 -85
- data/lib/sequel/dataset/query.rb +428 -214
- data/lib/sequel/dataset/sql.rb +446 -339
- data/lib/sequel/deprecated.rb +14 -2
- data/lib/sequel/exceptions.rb +48 -16
- data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
- data/lib/sequel/extensions/_model_pg_row.rb +43 -0
- data/lib/sequel/extensions/_pretty_table.rb +10 -9
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +15 -11
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/blank.rb +2 -0
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/columns_introspection.rb +9 -4
- data/lib/sequel/extensions/connection_expiration.rb +99 -0
- data/lib/sequel/extensions/connection_validator.rb +26 -13
- data/lib/sequel/extensions/constant_sql_override.rb +65 -0
- data/lib/sequel/extensions/constraint_validations.rb +93 -38
- data/lib/sequel/extensions/core_extensions.rb +45 -53
- data/lib/sequel/extensions/core_refinements.rb +44 -46
- data/lib/sequel/extensions/current_datetime_timestamp.rb +5 -4
- data/lib/sequel/extensions/dataset_source_alias.rb +4 -0
- data/lib/sequel/extensions/date_arithmetic.rb +42 -16
- data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +94 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -3
- data/lib/sequel/extensions/error_sql.rb +7 -3
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +14 -15
- data/lib/sequel/extensions/exclude_or_null.rb +68 -0
- data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
- data/lib/sequel/extensions/freeze_datasets.rb +3 -0
- data/lib/sequel/extensions/from_block.rb +2 -31
- data/lib/sequel/extensions/graph_each.rb +19 -6
- data/lib/sequel/extensions/identifier_mangling.rb +180 -0
- data/lib/sequel/extensions/implicit_subquery.rb +48 -0
- data/lib/sequel/extensions/index_caching.rb +109 -0
- data/lib/sequel/extensions/inflector.rb +8 -4
- data/lib/sequel/extensions/integer64.rb +32 -0
- data/lib/sequel/extensions/looser_typecasting.rb +19 -9
- data/lib/sequel/extensions/migration.rb +132 -80
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +4 -0
- data/lib/sequel/extensions/named_timezones.rb +88 -23
- data/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +12 -8
- data/lib/sequel/extensions/pagination.rb +35 -28
- data/lib/sequel/extensions/pg_array.rb +227 -316
- data/lib/sequel/extensions/pg_array_ops.rb +19 -7
- data/lib/sequel/extensions/pg_enum.rb +69 -24
- data/lib/sequel/extensions/pg_extended_date_support.rb +250 -0
- data/lib/sequel/extensions/pg_hstore.rb +50 -59
- data/lib/sequel/extensions/pg_hstore_ops.rb +9 -3
- data/lib/sequel/extensions/pg_inet.rb +34 -15
- data/lib/sequel/extensions/pg_inet_ops.rb +5 -1
- data/lib/sequel/extensions/pg_interval.rb +26 -26
- data/lib/sequel/extensions/pg_json.rb +422 -141
- data/lib/sequel/extensions/pg_json_ops.rb +248 -9
- data/lib/sequel/extensions/pg_loose_count.rb +5 -1
- data/lib/sequel/extensions/pg_range.rb +162 -146
- data/lib/sequel/extensions/pg_range_ops.rb +10 -5
- data/lib/sequel/extensions/pg_row.rb +53 -87
- data/lib/sequel/extensions/pg_row_ops.rb +36 -13
- data/lib/sequel/extensions/pg_static_cache_updater.rb +6 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
- data/lib/sequel/extensions/pretty_table.rb +4 -0
- data/lib/sequel/extensions/query.rb +12 -7
- data/lib/sequel/extensions/round_timestamps.rb +6 -9
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +59 -0
- data/lib/sequel/extensions/schema_caching.rb +14 -1
- data/lib/sequel/extensions/schema_dumper.rb +83 -55
- data/lib/sequel/extensions/select_remove.rb +8 -4
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
- data/lib/sequel/extensions/server_block.rb +50 -17
- data/lib/sequel/extensions/server_logging.rb +61 -0
- data/lib/sequel/extensions/split_array_nil.rb +8 -4
- data/lib/sequel/extensions/sql_comments.rb +96 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -1
- data/lib/sequel/extensions/string_agg.rb +181 -0
- data/lib/sequel/extensions/string_date_time.rb +2 -0
- data/lib/sequel/extensions/symbol_aref.rb +53 -0
- data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
- data/lib/sequel/extensions/symbol_as.rb +23 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
- data/lib/sequel/extensions/synchronize_sql.rb +45 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +4 -0
- data/lib/sequel/extensions/to_dot.rb +15 -5
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model.rb +36 -126
- data/lib/sequel/model/associations.rb +850 -257
- data/lib/sequel/model/base.rb +652 -764
- data/lib/sequel/model/dataset_module.rb +13 -10
- data/lib/sequel/model/default_inflections.rb +3 -1
- data/lib/sequel/model/errors.rb +3 -3
- data/lib/sequel/model/exceptions.rb +12 -12
- data/lib/sequel/model/inflections.rb +8 -19
- data/lib/sequel/model/plugins.rb +111 -0
- data/lib/sequel/plugins/accessed_columns.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +32 -7
- data/lib/sequel/plugins/after_initialize.rb +3 -1
- data/lib/sequel/plugins/association_dependencies.rb +27 -18
- data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
- data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
- data/lib/sequel/plugins/association_pks.rb +181 -83
- data/lib/sequel/plugins/association_proxies.rb +33 -9
- data/lib/sequel/plugins/auto_validations.rb +58 -23
- data/lib/sequel/plugins/before_after_save.rb +8 -0
- data/lib/sequel/plugins/blacklist_security.rb +23 -12
- data/lib/sequel/plugins/boolean_readers.rb +9 -6
- data/lib/sequel/plugins/boolean_subsets.rb +64 -0
- data/lib/sequel/plugins/caching.rb +27 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +192 -94
- data/lib/sequel/plugins/column_conflicts.rb +18 -3
- data/lib/sequel/plugins/column_select.rb +9 -5
- data/lib/sequel/plugins/columns_updated.rb +42 -0
- data/lib/sequel/plugins/composition.rb +36 -24
- data/lib/sequel/plugins/constraint_validations.rb +37 -16
- data/lib/sequel/plugins/csv_serializer.rb +58 -35
- data/lib/sequel/plugins/dataset_associations.rb +60 -18
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/defaults_setter.rb +74 -13
- data/lib/sequel/plugins/delay_add_association.rb +4 -1
- data/lib/sequel/plugins/dirty.rb +65 -24
- data/lib/sequel/plugins/eager_each.rb +27 -3
- data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
- data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
- data/lib/sequel/plugins/error_splitter.rb +19 -12
- data/lib/sequel/plugins/finder.rb +246 -0
- data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
- data/lib/sequel/plugins/force_encoding.rb +9 -12
- data/lib/sequel/plugins/hook_class_methods.rb +39 -54
- data/lib/sequel/plugins/input_transformer.rb +20 -10
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/insert_returning_select.rb +4 -2
- data/lib/sequel/plugins/instance_filters.rb +12 -8
- data/lib/sequel/plugins/instance_hooks.rb +36 -17
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/inverted_subsets.rb +24 -13
- data/lib/sequel/plugins/json_serializer.rb +123 -47
- data/lib/sequel/plugins/lazy_attributes.rb +20 -14
- data/lib/sequel/plugins/list.rb +40 -26
- data/lib/sequel/plugins/many_through_many.rb +28 -12
- data/lib/sequel/plugins/modification_detection.rb +17 -5
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -5
- data/lib/sequel/plugins/nested_attributes.rb +55 -28
- data/lib/sequel/plugins/optimistic_locking.rb +5 -3
- data/lib/sequel/plugins/pg_array_associations.rb +52 -18
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +348 -0
- data/lib/sequel/plugins/pg_row.rb +7 -51
- data/lib/sequel/plugins/prepared_statements.rb +53 -72
- data/lib/sequel/plugins/prepared_statements_safe.rb +13 -5
- data/lib/sequel/plugins/rcte_tree.rb +43 -63
- data/lib/sequel/plugins/serialization.rb +37 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +3 -1
- data/lib/sequel/plugins/sharding.rb +17 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +62 -28
- data/lib/sequel/plugins/singular_table_names.rb +2 -0
- data/lib/sequel/plugins/skip_create_refresh.rb +5 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/split_values.rb +13 -6
- data/lib/sequel/plugins/static_cache.rb +79 -53
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +5 -3
- data/lib/sequel/plugins/subclasses.rb +20 -2
- data/lib/sequel/plugins/subset_conditions.rb +48 -0
- data/lib/sequel/plugins/table_select.rb +4 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +120 -6
- data/lib/sequel/plugins/throw_failures.rb +110 -0
- data/lib/sequel/plugins/timestamps.rb +22 -8
- data/lib/sequel/plugins/touch.rb +21 -8
- data/lib/sequel/plugins/tree.rb +57 -30
- data/lib/sequel/plugins/typecast_on_load.rb +14 -4
- data/lib/sequel/plugins/unlimited_update.rb +3 -7
- data/lib/sequel/plugins/update_or_create.rb +6 -4
- data/lib/sequel/plugins/update_primary_key.rb +3 -1
- data/lib/sequel/plugins/update_refresh.rb +28 -15
- data/lib/sequel/plugins/uuid.rb +70 -0
- data/lib/sequel/plugins/validate_associated.rb +20 -0
- data/lib/sequel/plugins/validation_class_methods.rb +40 -19
- data/lib/sequel/plugins/validation_contexts.rb +49 -0
- data/lib/sequel/plugins/validation_helpers.rb +49 -31
- data/lib/sequel/plugins/whitelist_security.rb +122 -0
- data/lib/sequel/plugins/xml_serializer.rb +31 -30
- data/lib/sequel/sql.rb +479 -329
- data/lib/sequel/timezones.rb +62 -32
- data/lib/sequel/version.rb +10 -3
- metadata +177 -477
- data/Rakefile +0 -165
- data/doc/active_record.rdoc +0 -912
- data/doc/release_notes/1.0.txt +0 -38
- data/doc/release_notes/1.1.txt +0 -143
- data/doc/release_notes/1.3.txt +0 -101
- data/doc/release_notes/1.4.0.txt +0 -53
- data/doc/release_notes/1.5.0.txt +0 -155
- data/doc/release_notes/2.0.0.txt +0 -298
- data/doc/release_notes/2.1.0.txt +0 -271
- data/doc/release_notes/2.10.0.txt +0 -328
- data/doc/release_notes/2.11.0.txt +0 -215
- data/doc/release_notes/2.12.0.txt +0 -534
- data/doc/release_notes/2.2.0.txt +0 -253
- data/doc/release_notes/2.3.0.txt +0 -88
- data/doc/release_notes/2.4.0.txt +0 -106
- data/doc/release_notes/2.5.0.txt +0 -137
- data/doc/release_notes/2.6.0.txt +0 -157
- data/doc/release_notes/2.7.0.txt +0 -166
- data/doc/release_notes/2.8.0.txt +0 -171
- data/doc/release_notes/2.9.0.txt +0 -97
- data/doc/release_notes/3.0.0.txt +0 -221
- data/doc/release_notes/3.1.0.txt +0 -406
- data/doc/release_notes/3.10.0.txt +0 -286
- data/doc/release_notes/3.11.0.txt +0 -254
- data/doc/release_notes/3.12.0.txt +0 -304
- data/doc/release_notes/3.13.0.txt +0 -210
- data/doc/release_notes/3.14.0.txt +0 -118
- data/doc/release_notes/3.15.0.txt +0 -78
- data/doc/release_notes/3.16.0.txt +0 -45
- data/doc/release_notes/3.17.0.txt +0 -58
- data/doc/release_notes/3.18.0.txt +0 -120
- data/doc/release_notes/3.19.0.txt +0 -67
- data/doc/release_notes/3.2.0.txt +0 -268
- data/doc/release_notes/3.20.0.txt +0 -41
- data/doc/release_notes/3.21.0.txt +0 -87
- data/doc/release_notes/3.22.0.txt +0 -39
- data/doc/release_notes/3.23.0.txt +0 -172
- data/doc/release_notes/3.24.0.txt +0 -420
- data/doc/release_notes/3.25.0.txt +0 -88
- data/doc/release_notes/3.26.0.txt +0 -88
- data/doc/release_notes/3.27.0.txt +0 -82
- data/doc/release_notes/3.28.0.txt +0 -304
- data/doc/release_notes/3.29.0.txt +0 -459
- data/doc/release_notes/3.3.0.txt +0 -192
- data/doc/release_notes/3.30.0.txt +0 -135
- data/doc/release_notes/3.31.0.txt +0 -146
- data/doc/release_notes/3.32.0.txt +0 -202
- data/doc/release_notes/3.33.0.txt +0 -157
- data/doc/release_notes/3.34.0.txt +0 -671
- data/doc/release_notes/3.35.0.txt +0 -144
- data/doc/release_notes/3.36.0.txt +0 -245
- data/doc/release_notes/3.37.0.txt +0 -338
- data/doc/release_notes/3.38.0.txt +0 -234
- data/doc/release_notes/3.39.0.txt +0 -237
- data/doc/release_notes/3.4.0.txt +0 -325
- data/doc/release_notes/3.40.0.txt +0 -73
- data/doc/release_notes/3.41.0.txt +0 -155
- data/doc/release_notes/3.42.0.txt +0 -74
- data/doc/release_notes/3.43.0.txt +0 -105
- data/doc/release_notes/3.44.0.txt +0 -152
- data/doc/release_notes/3.45.0.txt +0 -179
- data/doc/release_notes/3.46.0.txt +0 -122
- data/doc/release_notes/3.47.0.txt +0 -270
- data/doc/release_notes/3.48.0.txt +0 -477
- data/doc/release_notes/3.5.0.txt +0 -510
- data/doc/release_notes/3.6.0.txt +0 -366
- data/doc/release_notes/3.7.0.txt +0 -179
- data/doc/release_notes/3.8.0.txt +0 -151
- data/doc/release_notes/3.9.0.txt +0 -233
- data/doc/release_notes/4.0.0.txt +0 -262
- data/doc/release_notes/4.1.0.txt +0 -85
- data/doc/release_notes/4.10.0.txt +0 -226
- data/doc/release_notes/4.11.0.txt +0 -147
- data/doc/release_notes/4.12.0.txt +0 -105
- data/doc/release_notes/4.13.0.txt +0 -169
- data/doc/release_notes/4.14.0.txt +0 -68
- data/doc/release_notes/4.15.0.txt +0 -56
- data/doc/release_notes/4.16.0.txt +0 -36
- data/doc/release_notes/4.17.0.txt +0 -38
- data/doc/release_notes/4.18.0.txt +0 -36
- data/doc/release_notes/4.19.0.txt +0 -45
- data/doc/release_notes/4.2.0.txt +0 -129
- data/doc/release_notes/4.20.0.txt +0 -79
- data/doc/release_notes/4.21.0.txt +0 -94
- data/doc/release_notes/4.22.0.txt +0 -72
- data/doc/release_notes/4.23.0.txt +0 -65
- data/doc/release_notes/4.24.0.txt +0 -99
- data/doc/release_notes/4.25.0.txt +0 -181
- data/doc/release_notes/4.26.0.txt +0 -44
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.4.0.txt +0 -92
- data/doc/release_notes/4.5.0.txt +0 -34
- data/doc/release_notes/4.6.0.txt +0 -30
- data/doc/release_notes/4.7.0.txt +0 -103
- data/doc/release_notes/4.8.0.txt +0 -175
- data/doc/release_notes/4.9.0.txt +0 -190
- data/lib/sequel/adapters/cubrid.rb +0 -142
- data/lib/sequel/adapters/do.rb +0 -156
- data/lib/sequel/adapters/do/mysql.rb +0 -64
- data/lib/sequel/adapters/do/postgres.rb +0 -42
- data/lib/sequel/adapters/do/sqlite3.rb +0 -40
- data/lib/sequel/adapters/jdbc/as400.rb +0 -82
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -62
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -34
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -31
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -31
- data/lib/sequel/adapters/odbc/progress.rb +0 -8
- data/lib/sequel/adapters/shared/cubrid.rb +0 -243
- data/lib/sequel/adapters/shared/firebird.rb +0 -245
- data/lib/sequel/adapters/shared/informix.rb +0 -52
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -150
- data/lib/sequel/adapters/shared/progress.rb +0 -38
- data/lib/sequel/adapters/swift.rb +0 -158
- data/lib/sequel/adapters/swift/mysql.rb +0 -47
- data/lib/sequel/adapters/swift/postgres.rb +0 -45
- data/lib/sequel/adapters/swift/sqlite.rb +0 -47
- data/lib/sequel/adapters/utils/pg_types.rb +0 -68
- data/lib/sequel/dataset/mutation.rb +0 -109
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -3
- data/lib/sequel/extensions/filter_having.rb +0 -59
- data/lib/sequel/extensions/hash_aliases.rb +0 -45
- data/lib/sequel/extensions/meta_def.rb +0 -31
- data/lib/sequel/extensions/query_literals.rb +0 -80
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -22
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -118
- data/lib/sequel/extensions/set_overrides.rb +0 -72
- data/lib/sequel/no_core_ext.rb +0 -1
- data/lib/sequel/plugins/association_autoreloading.rb +0 -7
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -7
- data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -78
- data/lib/sequel/plugins/prepared_statements_associations.rb +0 -117
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -59
- data/lib/sequel/plugins/schema.rb +0 -80
- data/lib/sequel/plugins/scissors.rb +0 -33
- data/spec/adapters/db2_spec.rb +0 -160
- data/spec/adapters/firebird_spec.rb +0 -411
- data/spec/adapters/informix_spec.rb +0 -100
- data/spec/adapters/mssql_spec.rb +0 -706
- data/spec/adapters/mysql_spec.rb +0 -1287
- data/spec/adapters/oracle_spec.rb +0 -313
- data/spec/adapters/postgres_spec.rb +0 -3725
- data/spec/adapters/spec_helper.rb +0 -43
- data/spec/adapters/sqlanywhere_spec.rb +0 -170
- data/spec/adapters/sqlite_spec.rb +0 -653
- data/spec/bin_spec.rb +0 -254
- data/spec/core/connection_pool_spec.rb +0 -1016
- data/spec/core/database_spec.rb +0 -2531
- data/spec/core/dataset_spec.rb +0 -5098
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1243
- data/spec/core/mock_adapter_spec.rb +0 -462
- data/spec/core/object_graph_spec.rb +0 -303
- data/spec/core/placeholder_literalizer_spec.rb +0 -163
- data/spec/core/schema_generator_spec.rb +0 -179
- data/spec/core/schema_spec.rb +0 -1659
- data/spec/core/spec_helper.rb +0 -34
- data/spec/core/version_spec.rb +0 -7
- data/spec/core_extensions_spec.rb +0 -699
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -123
- data/spec/extensions/after_initialize_spec.rb +0 -24
- data/spec/extensions/arbitrary_servers_spec.rb +0 -109
- data/spec/extensions/association_dependencies_spec.rb +0 -117
- data/spec/extensions/association_pks_spec.rb +0 -365
- data/spec/extensions/association_proxies_spec.rb +0 -86
- data/spec/extensions/auto_validations_spec.rb +0 -192
- data/spec/extensions/blacklist_security_spec.rb +0 -88
- data/spec/extensions/blank_spec.rb +0 -69
- data/spec/extensions/boolean_readers_spec.rb +0 -93
- data/spec/extensions/caching_spec.rb +0 -270
- data/spec/extensions/class_table_inheritance_spec.rb +0 -420
- data/spec/extensions/column_conflicts_spec.rb +0 -60
- data/spec/extensions/column_select_spec.rb +0 -108
- data/spec/extensions/columns_introspection_spec.rb +0 -91
- data/spec/extensions/composition_spec.rb +0 -242
- data/spec/extensions/connection_validator_spec.rb +0 -120
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -274
- data/spec/extensions/constraint_validations_spec.rb +0 -325
- data/spec/extensions/core_refinements_spec.rb +0 -519
- data/spec/extensions/csv_serializer_spec.rb +0 -173
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -311
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -150
- data/spec/extensions/defaults_setter_spec.rb +0 -101
- data/spec/extensions/delay_add_association_spec.rb +0 -52
- data/spec/extensions/dirty_spec.rb +0 -180
- data/spec/extensions/eager_each_spec.rb +0 -42
- data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
- data/spec/extensions/error_splitter_spec.rb +0 -18
- data/spec/extensions/error_sql_spec.rb +0 -20
- data/spec/extensions/eval_inspect_spec.rb +0 -73
- data/spec/extensions/filter_having_spec.rb +0 -40
- data/spec/extensions/force_encoding_spec.rb +0 -114
- data/spec/extensions/from_block_spec.rb +0 -21
- data/spec/extensions/graph_each_spec.rb +0 -109
- data/spec/extensions/hash_aliases_spec.rb +0 -24
- data/spec/extensions/hook_class_methods_spec.rb +0 -429
- data/spec/extensions/inflector_spec.rb +0 -183
- data/spec/extensions/input_transformer_spec.rb +0 -54
- data/spec/extensions/insert_returning_select_spec.rb +0 -46
- data/spec/extensions/instance_filters_spec.rb +0 -79
- data/spec/extensions/instance_hooks_spec.rb +0 -276
- data/spec/extensions/inverted_subsets_spec.rb +0 -33
- data/spec/extensions/json_serializer_spec.rb +0 -291
- data/spec/extensions/lazy_attributes_spec.rb +0 -170
- data/spec/extensions/list_spec.rb +0 -267
- data/spec/extensions/looser_typecasting_spec.rb +0 -43
- data/spec/extensions/many_through_many_spec.rb +0 -2172
- data/spec/extensions/meta_def_spec.rb +0 -21
- data/spec/extensions/migration_spec.rb +0 -712
- data/spec/extensions/modification_detection_spec.rb +0 -80
- data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
- data/spec/extensions/named_timezones_spec.rb +0 -108
- data/spec/extensions/nested_attributes_spec.rb +0 -697
- data/spec/extensions/null_dataset_spec.rb +0 -85
- data/spec/extensions/optimistic_locking_spec.rb +0 -128
- data/spec/extensions/pagination_spec.rb +0 -118
- data/spec/extensions/pg_array_associations_spec.rb +0 -736
- data/spec/extensions/pg_array_ops_spec.rb +0 -143
- data/spec/extensions/pg_array_spec.rb +0 -395
- data/spec/extensions/pg_enum_spec.rb +0 -92
- data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
- data/spec/extensions/pg_hstore_spec.rb +0 -206
- data/spec/extensions/pg_inet_ops_spec.rb +0 -101
- data/spec/extensions/pg_inet_spec.rb +0 -52
- data/spec/extensions/pg_interval_spec.rb +0 -76
- data/spec/extensions/pg_json_ops_spec.rb +0 -229
- data/spec/extensions/pg_json_spec.rb +0 -218
- data/spec/extensions/pg_loose_count_spec.rb +0 -17
- data/spec/extensions/pg_range_ops_spec.rb +0 -58
- data/spec/extensions/pg_range_spec.rb +0 -404
- data/spec/extensions/pg_row_ops_spec.rb +0 -60
- data/spec/extensions/pg_row_plugin_spec.rb +0 -62
- data/spec/extensions/pg_row_spec.rb +0 -360
- data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
- data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
- data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
- data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
- data/spec/extensions/prepared_statements_spec.rb +0 -103
- data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
- data/spec/extensions/pretty_table_spec.rb +0 -92
- data/spec/extensions/query_literals_spec.rb +0 -183
- data/spec/extensions/query_spec.rb +0 -102
- data/spec/extensions/rcte_tree_spec.rb +0 -392
- data/spec/extensions/round_timestamps_spec.rb +0 -43
- data/spec/extensions/schema_caching_spec.rb +0 -41
- data/spec/extensions/schema_dumper_spec.rb +0 -789
- data/spec/extensions/schema_spec.rb +0 -117
- data/spec/extensions/scissors_spec.rb +0 -26
- data/spec/extensions/select_remove_spec.rb +0 -38
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
- data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
- data/spec/extensions/serialization_spec.rb +0 -362
- data/spec/extensions/server_block_spec.rb +0 -90
- data/spec/extensions/set_overrides_spec.rb +0 -61
- data/spec/extensions/sharding_spec.rb +0 -198
- data/spec/extensions/shared_caching_spec.rb +0 -175
- data/spec/extensions/single_table_inheritance_spec.rb +0 -297
- data/spec/extensions/singular_table_names_spec.rb +0 -22
- data/spec/extensions/skip_create_refresh_spec.rb +0 -17
- data/spec/extensions/spec_helper.rb +0 -71
- data/spec/extensions/split_array_nil_spec.rb +0 -24
- data/spec/extensions/split_values_spec.rb +0 -22
- data/spec/extensions/sql_expr_spec.rb +0 -60
- data/spec/extensions/static_cache_spec.rb +0 -361
- data/spec/extensions/string_date_time_spec.rb +0 -95
- data/spec/extensions/string_stripper_spec.rb +0 -68
- data/spec/extensions/subclasses_spec.rb +0 -66
- data/spec/extensions/table_select_spec.rb +0 -71
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -82
- data/spec/extensions/thread_local_timezones_spec.rb +0 -67
- data/spec/extensions/timestamps_spec.rb +0 -175
- data/spec/extensions/to_dot_spec.rb +0 -154
- data/spec/extensions/touch_spec.rb +0 -203
- data/spec/extensions/tree_spec.rb +0 -274
- data/spec/extensions/typecast_on_load_spec.rb +0 -80
- data/spec/extensions/unlimited_update_spec.rb +0 -20
- data/spec/extensions/update_or_create_spec.rb +0 -87
- data/spec/extensions/update_primary_key_spec.rb +0 -100
- data/spec/extensions/update_refresh_spec.rb +0 -53
- data/spec/extensions/validate_associated_spec.rb +0 -52
- data/spec/extensions/validation_class_methods_spec.rb +0 -1027
- data/spec/extensions/validation_helpers_spec.rb +0 -541
- data/spec/extensions/xml_serializer_spec.rb +0 -207
- data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
- data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
- data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
- data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
- data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
- data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
- data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
- data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
- data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
- data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
- data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/reversible_migrations/001_reversible.rb +0 -5
- data/spec/files/reversible_migrations/002_reversible.rb +0 -5
- data/spec/files/reversible_migrations/003_reversible.rb +0 -5
- data/spec/files/reversible_migrations/004_reversible.rb +0 -5
- data/spec/files/reversible_migrations/005_reversible.rb +0 -10
- data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
- data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
- data/spec/guards_helper.rb +0 -55
- data/spec/integration/associations_test.rb +0 -2454
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1808
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -240
- data/spec/integration/model_test.rb +0 -226
- data/spec/integration/plugin_test.rb +0 -2240
- data/spec/integration/prepared_statement_test.rb +0 -467
- data/spec/integration/schema_test.rb +0 -817
- data/spec/integration/spec_helper.rb +0 -48
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -374
- data/spec/integration/type_test.rb +0 -133
- data/spec/model/association_reflection_spec.rb +0 -525
- data/spec/model/associations_spec.rb +0 -4426
- data/spec/model/base_spec.rb +0 -759
- data/spec/model/class_dataset_methods_spec.rb +0 -146
- data/spec/model/dataset_methods_spec.rb +0 -149
- data/spec/model/eager_loading_spec.rb +0 -2137
- data/spec/model/hooks_spec.rb +0 -604
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -982
- data/spec/model/plugins_spec.rb +0 -299
- data/spec/model/record_spec.rb +0 -2147
- data/spec/model/spec_helper.rb +0 -46
- data/spec/model/validations_spec.rb +0 -193
- data/spec/sequel_coverage.rb +0 -15
- data/spec/spec_config.rb +0 -10
data/bin/sequel
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen-string-literal: true
|
|
2
3
|
|
|
3
|
-
require 'rubygems'
|
|
4
4
|
require 'optparse'
|
|
5
5
|
|
|
6
6
|
code = nil
|
|
7
7
|
copy_databases = nil
|
|
8
8
|
dump_migration = nil
|
|
9
9
|
dump_schema = nil
|
|
10
|
+
dump_indexes = nil
|
|
10
11
|
env = nil
|
|
11
12
|
migrate_dir = nil
|
|
12
13
|
migrate_ver = nil
|
|
@@ -83,7 +84,7 @@ options = OptionParser.new do |opts|
|
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
opts.on("-M", "--migrate-version VER", "migrate the database to version given") do |v|
|
|
86
|
-
migrate_ver = Integer(v)
|
|
87
|
+
migrate_ver = Integer(v, 10)
|
|
87
88
|
end
|
|
88
89
|
|
|
89
90
|
opts.on("-N", "--no-test-connection", "do not test the connection") do
|
|
@@ -106,6 +107,11 @@ options = OptionParser.new do |opts|
|
|
|
106
107
|
opts.on_tail("-v", "--version", "Show version") do
|
|
107
108
|
show_version = true
|
|
108
109
|
end
|
|
110
|
+
|
|
111
|
+
opts.on("-X", "--dump-indexes filename", "dump the index cache for all tables to the file") do |v|
|
|
112
|
+
dump_indexes = v
|
|
113
|
+
exclusive_options << :X
|
|
114
|
+
end
|
|
109
115
|
end
|
|
110
116
|
opts = options
|
|
111
117
|
opts.parse!
|
|
@@ -116,26 +122,27 @@ error_proc = lambda do |msg|
|
|
|
116
122
|
$stderr.puts(msg)
|
|
117
123
|
exit 1
|
|
118
124
|
end
|
|
125
|
+
extra_proc = lambda do
|
|
126
|
+
$stderr.puts("Warning: last #{ARGV.length} arguments ignored") unless ARGV.empty?
|
|
127
|
+
end
|
|
119
128
|
|
|
120
129
|
error_proc["Error: Must specify -m if using -M"] if migrate_ver && !migrate_dir
|
|
121
130
|
error_proc["Error: Cannot specify #{exclusive_options.map{|v| "-#{v}"}.join(' and ')} together"] if exclusive_options.length > 1
|
|
122
131
|
|
|
123
132
|
connect_proc = lambda do |database|
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
db_opts = {:test=>test, :loggers=>loggers}
|
|
134
|
+
if database.nil? || database.empty?
|
|
135
|
+
Sequel.connect('mock:///', db_opts)
|
|
126
136
|
elsif File.exist?(database)
|
|
127
137
|
require 'yaml'
|
|
128
138
|
env ||= "development"
|
|
129
139
|
db_config = YAML.load_file(database)
|
|
130
140
|
db_config = db_config[env] || db_config[env.to_sym] || db_config
|
|
131
141
|
db_config.keys.each{|k| db_config[k.to_sym] = db_config.delete(k)}
|
|
132
|
-
Sequel.connect(db_config)
|
|
142
|
+
Sequel.connect(db_config, db_opts)
|
|
133
143
|
else
|
|
134
|
-
Sequel.connect(database)
|
|
144
|
+
Sequel.connect(database, db_opts)
|
|
135
145
|
end
|
|
136
|
-
db.loggers = loggers
|
|
137
|
-
db.test_connection if test
|
|
138
|
-
db
|
|
139
146
|
end
|
|
140
147
|
|
|
141
148
|
begin
|
|
@@ -151,32 +158,47 @@ begin
|
|
|
151
158
|
DB = connect_proc[db]
|
|
152
159
|
load_dirs.each{|d| d.is_a?(Array) ? require(d.first) : Dir["#{d}/**/*.rb"].each{|f| load(f)}}
|
|
153
160
|
if migrate_dir
|
|
161
|
+
extra_proc.call
|
|
154
162
|
Sequel.extension :migration, :core_extensions
|
|
155
163
|
Sequel::Migrator.apply(DB, migrate_dir, migrate_ver)
|
|
156
164
|
exit
|
|
157
165
|
end
|
|
158
166
|
if dump_migration
|
|
167
|
+
extra_proc.call
|
|
159
168
|
DB.extension :schema_dumper
|
|
160
169
|
puts DB.dump_schema_migration(:same_db=>dump_migration==:same_db)
|
|
161
170
|
exit
|
|
162
171
|
end
|
|
163
172
|
if dump_schema
|
|
173
|
+
extra_proc.call
|
|
164
174
|
DB.extension :schema_caching
|
|
165
175
|
DB.tables.each{|t| DB.schema(Sequel::SQL::Identifier.new(t))}
|
|
166
176
|
DB.dump_schema_cache(dump_schema)
|
|
167
177
|
exit
|
|
168
178
|
end
|
|
179
|
+
if dump_indexes
|
|
180
|
+
extra_proc.call
|
|
181
|
+
DB.extension :index_caching
|
|
182
|
+
DB.tables.each{|t| DB.indexes(Sequel::SQL::Identifier.new(t))}
|
|
183
|
+
DB.dump_index_cache(dump_indexes)
|
|
184
|
+
exit
|
|
185
|
+
end
|
|
169
186
|
if copy_databases
|
|
170
187
|
Sequel.extension :migration
|
|
171
188
|
DB.extension :schema_dumper
|
|
172
189
|
|
|
173
190
|
db2 = ARGV.shift
|
|
174
191
|
error_proc["Error: Must specify database connection string or path to yaml file as second argument for database you want to copy to"] if db2.nil? || db2.empty?
|
|
192
|
+
extra_proc.call
|
|
175
193
|
start_time = Time.now
|
|
176
194
|
TO_DB = connect_proc[db2]
|
|
177
195
|
same_db = DB.database_type==TO_DB.database_type
|
|
178
196
|
index_opts = {:same_db=>same_db}
|
|
179
197
|
index_opts[:index_names] = :namespace if !DB.global_index_namespace? && TO_DB.global_index_namespace?
|
|
198
|
+
if DB.database_type == :sqlite && !same_db
|
|
199
|
+
# SQLite integer types allows 64-bit integers
|
|
200
|
+
TO_DB.extension :integer64
|
|
201
|
+
end
|
|
180
202
|
|
|
181
203
|
puts "Databases connections successful"
|
|
182
204
|
schema_migration = eval(DB.dump_schema_migration(:indexes=>false, :same_db=>same_db))
|
|
@@ -225,6 +247,7 @@ begin
|
|
|
225
247
|
exit
|
|
226
248
|
end
|
|
227
249
|
if code
|
|
250
|
+
extra_proc.call
|
|
228
251
|
eval(code)
|
|
229
252
|
exit
|
|
230
253
|
end
|
|
@@ -1,26 +1,149 @@
|
|
|
1
1
|
= Advanced Associations
|
|
2
2
|
|
|
3
|
-
Sequel::Model
|
|
3
|
+
Sequel::Model's association support is powerful and flexible, but it can be difficult for
|
|
4
|
+
new users to understand what the support enables. This guide shows off some of the more
|
|
5
|
+
advanced Sequel::Model association features.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
You should probably review the {Model Associations Basics and Options guide}[rdoc-ref:doc/association_basics.rdoc]
|
|
8
|
+
before reviewing this guide.
|
|
9
|
+
|
|
10
|
+
== Sequel::Model Eager Loading
|
|
11
|
+
|
|
12
|
+
Sequel::Model offers two different ways to perform eager loading, +eager+ and
|
|
13
|
+
+eager_graph+. +eager+ uses an SQL query per association, +eager_graph+ uses a single
|
|
14
|
+
SQL query containing JOINs.
|
|
15
|
+
|
|
16
|
+
Assuming the following associations:
|
|
17
|
+
|
|
18
|
+
Artist.one_to_many :albums
|
|
19
|
+
Album.one_to_many :tracks
|
|
20
|
+
Tracks.many_to_one :lyric
|
|
21
|
+
|
|
22
|
+
Let's say you wanted to load all artists and eagerly load the related albums, tracks, and lyrics.
|
|
23
|
+
|
|
24
|
+
Artist.eager(albums: {tracks: :lyric})
|
|
25
|
+
# 4 Queries:
|
|
26
|
+
# SELECT * FROM artists;
|
|
27
|
+
# SELECT * FROM albums WHERE (artist_id IN (...));
|
|
28
|
+
# SELECT * FROM tracks WHERE (album_id IN (...));
|
|
29
|
+
# SELECT * FROM lyrics WHERE (id IN (...));
|
|
30
|
+
|
|
31
|
+
Artist.eager_graph(albums: {tracks: :lyric})
|
|
32
|
+
# 1 Query:
|
|
33
|
+
# SELECT artists.id, artists.name, ...
|
|
34
|
+
# albums.id AS albums_id, albums.name AS albums_name, ...
|
|
35
|
+
# tracks.id AS tracks_id, tracks.name AS tracks_name, ...
|
|
36
|
+
# lyric.id AS lyric_id, ...
|
|
37
|
+
# FROM artists
|
|
38
|
+
# LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
|
39
|
+
# LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
|
|
40
|
+
# LEFT OUTER JOIN lyrics AS lyric ON (lyric.id = tracks.lyric_id);
|
|
41
|
+
|
|
42
|
+
In general, the recommendation is to use +eager+ unless you have a reason to use +eager_graph+.
|
|
43
|
+
+eager_graph+ is needed when you want to reference columns in an associated table. For example,
|
|
44
|
+
if you want to order the loading of returned artists based on the names of the albums, you cannot
|
|
45
|
+
do:
|
|
46
|
+
|
|
47
|
+
Artist.eager(albums: {tracks: :lyric}).order{albums[:name]}
|
|
48
|
+
|
|
49
|
+
because the initial query Sequel will use would be:
|
|
50
|
+
|
|
51
|
+
# SELECT * FROM artists ORDER BY albums.name;
|
|
52
|
+
|
|
53
|
+
and +albums+ is not a valid qualifier in such a query. In this situation, you must use +eager_graph+:
|
|
54
|
+
|
|
55
|
+
Artist.eager_graph(albums: {tracks: :lyric}).order{albums[:name]}
|
|
56
|
+
|
|
57
|
+
Whether +eager+ or +eager_graph+ performs better is association and database dependent. If
|
|
58
|
+
you are concerned about performance, you should try benchmarking both cases with appropriate
|
|
59
|
+
data to see which performs better.
|
|
60
|
+
|
|
61
|
+
=== Mixing eager and eager_graph
|
|
62
|
+
|
|
63
|
+
Sequel offers the ability to mix +eager+ and +eager_graph+ when loading results. This can
|
|
64
|
+
be done at the main level by calling both +eager+ and +eager_graph+ on the same dataset:
|
|
65
|
+
|
|
66
|
+
Album.eager(:artist).eager_graph(:tracks)
|
|
67
|
+
# 2 Queries:
|
|
68
|
+
# SELECT albums.id, albums.name, ...
|
|
69
|
+
# artist.id AS artist_id, artist.name AS artist_name, ...
|
|
70
|
+
# FROM albums
|
|
71
|
+
# LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id);
|
|
72
|
+
# SELECT * FROM artists WHERE (id IN (...));
|
|
73
|
+
|
|
74
|
+
You can also use +eager+ to load initial associations, and +eager_graph+ to load
|
|
75
|
+
remaining associations, by using +eager_graph+ in an eager load callback:
|
|
76
|
+
|
|
77
|
+
Artist.eager(albums: {tracks: proc{|ds| ds.eager_graph(:lyric)}})
|
|
78
|
+
# 3 Queries:
|
|
79
|
+
# SELECT * FROM artists;
|
|
80
|
+
# SELECT * FROM albums WHERE (artist_id IN (...));
|
|
81
|
+
# SELECT tracks.id, tracks.name, ...
|
|
82
|
+
# lyric.id AS lyric_id, ...
|
|
83
|
+
# FROM tracks
|
|
84
|
+
# LEFT OUTER JOIN lyrics AS lyric ON (lyric.id = tracks.lyric_id)
|
|
85
|
+
# WHERE (tracks.album_id IN (...));
|
|
86
|
+
|
|
87
|
+
Using the +eager_graph_eager+ plugin, you can use +eager_graph+ to load the
|
|
88
|
+
initial associations, and +eager+ to load the remaining associations. When
|
|
89
|
+
you call +eager_graph_eager+, you must specify the dependency chain at
|
|
90
|
+
which to start the eager loading via +eager+:
|
|
91
|
+
|
|
92
|
+
Artist.plugin :eager_graph_eager
|
|
93
|
+
Artist.eager_graph(albums: :tracks).eager_graph_eager([:albums, :tracks], :lyric)
|
|
94
|
+
# 2 Queries:
|
|
95
|
+
# SELECT artists.id, artists.name, ...
|
|
96
|
+
# albums.id AS albums_id, albums.name AS albums_name, ...
|
|
97
|
+
# tracks.id AS tracks_id, tracks.name AS tracks_name, ...
|
|
98
|
+
# FROM artists
|
|
99
|
+
# LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
|
100
|
+
# LEFT OUTER JOIN tracks ON (tracks.album_id= albums.id);
|
|
101
|
+
# SELECT * FROM lyrics WHERE (id IN (...));
|
|
102
|
+
|
|
103
|
+
These two approaches can also be nested, with +eager+ -> +eager_graph+ -> +eager+:
|
|
104
|
+
|
|
105
|
+
Album.plugin :eager_graph_eager
|
|
106
|
+
Artist.eager(albums: proc{|ds| ds.eager_graph(:tracks).eager_graph_eager([:tracks], :lyric)})
|
|
107
|
+
# 3 Queries:
|
|
108
|
+
# SELECT * FROM artists;
|
|
109
|
+
# SELECT albums.id, albums.name, ...
|
|
110
|
+
# tracks.id AS tracks_id, tracks.name AS tracks_name, ...
|
|
111
|
+
# FROM albums
|
|
112
|
+
# LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
|
|
113
|
+
# WHERE (albums.artist_id IN (...));
|
|
114
|
+
# SELECT * FROM lyrics WHERE (id IN (...));
|
|
115
|
+
|
|
116
|
+
Or with 2 separate +eager_graph+ queries:
|
|
117
|
+
|
|
118
|
+
Artist.eager_graph(:albums).eager_graph_eager([:albums], :tracks=>proc{|ds| ds.eager_graph(:lyric)})
|
|
119
|
+
# 2 Queries:
|
|
120
|
+
# SELECT artists.id, artists.name, ...
|
|
121
|
+
# albums.id AS albums_id, albums.name AS albums_name, ...
|
|
122
|
+
# FROM artists
|
|
123
|
+
# LEFT OUTER JOIN albums ON (albums.artist_id = artists.id);
|
|
124
|
+
# SELECT tracks.id, tracks.name, ...
|
|
125
|
+
# lyric.id AS lyric_id, ...
|
|
126
|
+
# FROM tracks
|
|
127
|
+
# LEFT OUTER JOIN lyrics AS lyric ON (lyric.id = tracks.lyric_id)
|
|
128
|
+
# WHERE (tracks.album_id IN (...));
|
|
129
|
+
|
|
130
|
+
== Sequel::Model Association Loading Options
|
|
6
131
|
|
|
7
132
|
There are a bunch of advanced association options that are available to
|
|
8
|
-
handle more complex cases. First we'll go over some of
|
|
9
|
-
the simpler ones:
|
|
133
|
+
handle more complex cases. First we'll go over some of the simpler ones:
|
|
10
134
|
|
|
11
135
|
All associations take a block that can be used to further filter/modify the
|
|
12
|
-
default dataset
|
|
13
|
-
a different block when eager loading via <tt>Dataset#eager</tt>. Association blocks are
|
|
14
|
-
useful for things like:
|
|
136
|
+
default dataset:
|
|
15
137
|
|
|
16
|
-
Artist.one_to_many :gold_albums, :
|
|
138
|
+
Artist.one_to_many :gold_albums, class: :Album do |ds|
|
|
17
139
|
ds.where{copies_sold > 500000}
|
|
18
140
|
end
|
|
19
141
|
|
|
20
|
-
There
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
142
|
+
There's also an :eager_block option if you want to use a different block when
|
|
143
|
+
eager loading via <tt>Dataset#eager</tt>.
|
|
144
|
+
|
|
145
|
+
There are many options for changing how the association is eagerly
|
|
146
|
+
loaded via <tt>Dataset#eager_graph</tt>:
|
|
24
147
|
|
|
25
148
|
:graph_join_type :: The type of join to do (<tt>:inner</tt>, <tt>:left</tt>, <tt>:right</tt>)
|
|
26
149
|
:graph_conditions :: Additional conditions to put on join (needs to be a
|
|
@@ -42,28 +165,23 @@ These can be used like this:
|
|
|
42
165
|
|
|
43
166
|
# Makes Artist.eager_graph(:required_albums).all not return artists that
|
|
44
167
|
# don't have any albums
|
|
45
|
-
Artist.one_to_many :required_albums, :
|
|
168
|
+
Artist.one_to_many :required_albums, class: :Album, graph_join_type: :inner
|
|
46
169
|
|
|
47
170
|
# Makes sure all returned albums have the active flag set
|
|
48
|
-
Artist.one_to_many :active_albums, :
|
|
49
|
-
:graph_conditions=>{:active=>true}
|
|
171
|
+
Artist.one_to_many :active_albums, class: :Album, graph_conditions: {active: true}
|
|
50
172
|
|
|
51
173
|
# Only returns albums that have sold more than 500,000 copies
|
|
52
|
-
Artist.one_to_many :gold_albums, :
|
|
53
|
-
:
|
|
174
|
+
Artist.one_to_many :gold_albums, class: :Album,
|
|
175
|
+
graph_block: proc{|j,lj,js| Sequel[j][:copies_sold] > 500000}
|
|
54
176
|
|
|
55
177
|
# Handles the case where the tables are associated by a case insensitive name string
|
|
56
|
-
Artist.one_to_many :albums, :
|
|
57
|
-
:
|
|
58
|
-
:
|
|
178
|
+
Artist.one_to_many :albums, key: :artist_name,
|
|
179
|
+
graph_only_conditions: nil,
|
|
180
|
+
graph_block: proc{|j,lj,js| {Sequel.function(:lower, Sequel[j][:artist_name])=>Sequel.function(:lower, Sequel[lj][:name])}}
|
|
59
181
|
|
|
60
182
|
# Handles the case where both key columns have the name artist_name, and you want to use
|
|
61
183
|
# a JOIN USING
|
|
62
|
-
Artist.one_to_many :albums, :
|
|
63
|
-
|
|
64
|
-
Remember, using +eager_graph+ is generally only necessary when you need to
|
|
65
|
-
filter/order based on columns in an associated table, it is recommended to
|
|
66
|
-
use +eager+ for eager loading if possible.
|
|
184
|
+
Artist.one_to_many :albums, key: :artist_name, graph_only_conditions: [:artist_name]
|
|
67
185
|
|
|
68
186
|
One advantage of using +eager_graph+ is that you can easily filter/order
|
|
69
187
|
on columns in an associated table on a per-query basis, using regular
|
|
@@ -73,14 +191,16 @@ ordered by the albums name, you can do:
|
|
|
73
191
|
|
|
74
192
|
albums = Artist.
|
|
75
193
|
eager_graph(:albums).
|
|
76
|
-
where
|
|
77
|
-
order
|
|
194
|
+
where{Sequel.like(albums[:name], 'A%')}.
|
|
195
|
+
order{albums[:name]}.
|
|
78
196
|
all
|
|
79
197
|
|
|
80
198
|
For lazy loading (e.g. Model[1].association), the <tt>:dataset</tt> option can be used
|
|
81
199
|
to specify an arbitrary dataset (one that uses different keys, multiple keys,
|
|
82
200
|
joins to other tables, etc.).
|
|
83
201
|
|
|
202
|
+
== Custom Eager Loaders
|
|
203
|
+
|
|
84
204
|
For eager loading via +eager+, the <tt>:eager_loader</tt> option can be used to specify
|
|
85
205
|
how to eagerly load a complex association. This is an extremely powerful
|
|
86
206
|
option. Though it can often be verbose (compared to other things in Sequel),
|
|
@@ -211,7 +331,7 @@ and the tracks eager loader looks like:
|
|
|
211
331
|
Album.one_to_many :tracks, :eager_loader=>(proc do |eo_opts|
|
|
212
332
|
eo_opts[:rows].each{|album| album.associations[:tracks] = []}
|
|
213
333
|
id_map = eo_opts[:id_map]
|
|
214
|
-
Track.where(:
|
|
334
|
+
Track.where(:album_id=>id_map.keys).all do |track|
|
|
215
335
|
if albums = id_map[track.album_id]
|
|
216
336
|
albums.each do |album|
|
|
217
337
|
album.associations[:tracks] << track
|
|
@@ -244,7 +364,7 @@ loading.
|
|
|
244
364
|
|
|
245
365
|
Sequel supports specifying limits and/or offsets for associations:
|
|
246
366
|
|
|
247
|
-
Artist.one_to_many :first_10_albums, :
|
|
367
|
+
Artist.one_to_many :first_10_albums, class: :Album, order: :release_date, limit: 10
|
|
248
368
|
|
|
249
369
|
For retrieving the associated objects for a single object, this just uses
|
|
250
370
|
a LIMIT:
|
|
@@ -260,7 +380,7 @@ approach. Sequel has 4 separate strategies for dealing with such cases.
|
|
|
260
380
|
The default strategy used on all databases is a UNION-based approach, which
|
|
261
381
|
will submit multiple subqueries in a UNION query:
|
|
262
382
|
|
|
263
|
-
Artist.where(:
|
|
383
|
+
Artist.where(id: [1,2]).eager(:first_10_albums).all
|
|
264
384
|
# SELECT * FROM (SELECT * FROM albums WHERE (artist_id = 1) LIMIT 10) UNION ALL
|
|
265
385
|
# SELECT * FROM (SELECT * FROM albums WHERE (artist_id = 2) LIMIT 10)
|
|
266
386
|
|
|
@@ -272,9 +392,9 @@ index, you'll want to manually specify the :eager_limit_strategy option as shown
|
|
|
272
392
|
On PostgreSQL, for *_one associations that don't use an offset, you can
|
|
273
393
|
choose to use a the distinct on strategy:
|
|
274
394
|
|
|
275
|
-
Artist.one_to_one :first_album, :
|
|
276
|
-
:
|
|
277
|
-
Artist.where(:
|
|
395
|
+
Artist.one_to_one :first_album, class: :Album, order: :release_date,
|
|
396
|
+
eager_limit_strategy: :distinct_on
|
|
397
|
+
Artist.where(id: [1,2]).eager(:first_album).all
|
|
278
398
|
# SELECT DISTINCT ON (albums.artist_id) *
|
|
279
399
|
# FROM albums
|
|
280
400
|
# WHERE (albums.artist_id IN (1, 2))
|
|
@@ -283,13 +403,13 @@ choose to use a the distinct on strategy:
|
|
|
283
403
|
Otherwise, if the database supports window functions, you can choose to use
|
|
284
404
|
the window function strategy:
|
|
285
405
|
|
|
286
|
-
Artist.one_to_many :first_10_albums, :
|
|
287
|
-
:
|
|
406
|
+
Artist.one_to_many :first_10_albums, class: :Album, order: :release_date, limit: 10,
|
|
407
|
+
eager_limit_strategy: :window_function
|
|
288
408
|
Artist.where(:id=>[1,2]).eager(:first_10_albums).all
|
|
289
409
|
# SELECT * FROM (
|
|
290
|
-
# SELECT *, row_number() OVER (PARTITION BY
|
|
291
|
-
# FROM
|
|
292
|
-
# WHERE (
|
|
410
|
+
# SELECT *, row_number() OVER (PARTITION BY albums.artist_id ORDER BY release_date) AS x_sequel_row_number_x
|
|
411
|
+
# FROM albums
|
|
412
|
+
# WHERE (albums.artist_id IN (1, 2))
|
|
293
413
|
# ) AS t1
|
|
294
414
|
# WHERE (x_sequel_row_number_x <= 10)
|
|
295
415
|
|
|
@@ -297,6 +417,29 @@ Alternatively, you can use the :ruby strategy, which will fall back to
|
|
|
297
417
|
retrieving all records, and then will slice the resulting array to get
|
|
298
418
|
the first 10 after retrieval.
|
|
299
419
|
|
|
420
|
+
=== Dynamic Eager Loading Limits
|
|
421
|
+
|
|
422
|
+
If you need to eager load variable numbers of records (with limits that aren't
|
|
423
|
+
known at the time of the association definition), Sequel supports an
|
|
424
|
+
:eager_limit dataset option that can be defined in an eager loading callback:
|
|
425
|
+
|
|
426
|
+
Artist.one_to_many :albums
|
|
427
|
+
Artist.where(id: [1, 2]).eager(albums: lambda{|ds| ds.order(:release_date).clone(eager_limit: 3)}).all
|
|
428
|
+
# SELECT * FROM (
|
|
429
|
+
# SELECT *, row_number() OVER (PARTITION BY albums.artist_id ORDER BY release_date) AS x_sequel_row_number_x
|
|
430
|
+
# FROM albums
|
|
431
|
+
# WHERE (albums.artist_id IN (1, 2))
|
|
432
|
+
# ) AS t1
|
|
433
|
+
# WHERE (x_sequel_row_number_x <= 3)
|
|
434
|
+
|
|
435
|
+
You can also customize the :eager_limit_strategy on a case-by-case basis by passing in that option in the same way:
|
|
436
|
+
|
|
437
|
+
Artist.where(id: [1, 2]).eager(albums: lambda{|ds| ds.order(:release_date).clone(eager_limit: 3, eager_limit_strategy: :ruby)}).all
|
|
438
|
+
# SELECT * FROM albums WHERE (albums.artist_id IN (1, 2)) ORDER BY release_date
|
|
439
|
+
|
|
440
|
+
The :eager_limit and :eager_limit_strategy options currently only work when
|
|
441
|
+
eager loading via #eager, not with #eager_graph.
|
|
442
|
+
|
|
300
443
|
=== Eager Loading via eager_graph_with_options
|
|
301
444
|
|
|
302
445
|
When eager loading an association via eager_graph (which uses JOINs), the
|
|
@@ -310,7 +453,7 @@ eager_graph_with_options method with the :limit_strategy option.
|
|
|
310
453
|
The :distinct_on strategy uses DISTINCT ON in a subquery and JOINs that
|
|
311
454
|
subquery:
|
|
312
455
|
|
|
313
|
-
Artist.eager_graph_with_options(:first_album, :
|
|
456
|
+
Artist.eager_graph_with_options(:first_album, limit_strategy: :distinct_on).all
|
|
314
457
|
# SELECT artists.id, artists.name, first_album.id AS first_album_id,
|
|
315
458
|
# first_album.name AS first_album_name, first_album.artist_id,
|
|
316
459
|
# first_album.release_date
|
|
@@ -324,7 +467,7 @@ subquery:
|
|
|
324
467
|
The :window_function approach JOINs to a nested subquery using a window
|
|
325
468
|
function:
|
|
326
469
|
|
|
327
|
-
Artist.eager_graph_with_options(:first_10_albums, :
|
|
470
|
+
Artist.eager_graph_with_options(:first_10_albums, limit_strategy: :window_function).all
|
|
328
471
|
# SELECT artists.id, artists.name, first_10_albums.id AS first_10_albums_id,
|
|
329
472
|
# first_10_albums.name AS first_10_albums_name, first_10_albums.artist_id,
|
|
330
473
|
# first_10_albums.release_date
|
|
@@ -340,7 +483,7 @@ function:
|
|
|
340
483
|
The :correlated_subquery approach JOINs to a nested subquery using a correlated
|
|
341
484
|
subquery:
|
|
342
485
|
|
|
343
|
-
Artist.eager_graph_with_options(:first_10_albums, :limit_strategy
|
|
486
|
+
Artist.eager_graph_with_options(:first_10_albums, :limit_strategy=>:correlated_subquery).all
|
|
344
487
|
# SELECT artists.id, artists.name, first_10_albums.id AS first_10_albums_id,
|
|
345
488
|
# first_10_albums.name AS first_10_albums_name, first_10_albums.artist_id,
|
|
346
489
|
# first_10_albums.release_date
|
|
@@ -357,8 +500,6 @@ subquery:
|
|
|
357
500
|
# )
|
|
358
501
|
# ) AS first_10_albums ON (first_10_albums.artist_id = artists.id)
|
|
359
502
|
|
|
360
|
-
(SELECT * FROM tracks WHERE (tracks.id IN (SELECT t1.id FROM tracks AS t1 WHERE (t1.album_id = tracks.album_id) LIMIT 1)))
|
|
361
|
-
|
|
362
503
|
The reason that Sequel does not automatically use the :distinct_on, :window function
|
|
363
504
|
or :correlated_subquery strategy for eager_graph is that it can perform much worse than the
|
|
364
505
|
default of just doing the array slicing in ruby. If you are only using eager_graph to
|
|
@@ -380,7 +521,7 @@ strategy based on the database you are using, and you can override it using the
|
|
|
380
521
|
|
|
381
522
|
The :distinct_on strategy:
|
|
382
523
|
|
|
383
|
-
Artist.where(:
|
|
524
|
+
Artist.where(first_album: Album[1]).all
|
|
384
525
|
# SELECT *
|
|
385
526
|
# FROM artists
|
|
386
527
|
# WHERE (artists.id IN (
|
|
@@ -394,7 +535,7 @@ The :distinct_on strategy:
|
|
|
394
535
|
|
|
395
536
|
The :window_function strategy:
|
|
396
537
|
|
|
397
|
-
Artist.where(:
|
|
538
|
+
Artist.where(first_10_albums: Album[1]).all
|
|
398
539
|
# SELECT *
|
|
399
540
|
# FROM artists
|
|
400
541
|
# WHERE (artists.id IN (
|
|
@@ -410,7 +551,7 @@ The :window_function strategy:
|
|
|
410
551
|
|
|
411
552
|
The :correlated_subquery strategy:
|
|
412
553
|
|
|
413
|
-
Artist.where(:
|
|
554
|
+
Artist.where(first_10_albums: Album[1]).all
|
|
414
555
|
# SELECT *
|
|
415
556
|
# FROM artists
|
|
416
557
|
# WHERE (artists.id IN (
|
|
@@ -424,11 +565,11 @@ The :correlated_subquery strategy:
|
|
|
424
565
|
# LIMIT 1
|
|
425
566
|
# )) AND (albums.id = 1))))
|
|
426
567
|
|
|
427
|
-
Note that filtering by limited associations does not work on MySQL, as does not support
|
|
568
|
+
Note that filtering by limited associations does not work on MySQL, as MySQL does not support
|
|
428
569
|
any of the strategies. It's also not supported when using composite keys on databases
|
|
429
570
|
that don't support window functions and don't support multiple columns in IN.
|
|
430
571
|
|
|
431
|
-
|
|
572
|
+
=== Additional Association Types
|
|
432
573
|
|
|
433
574
|
While the above examples for limited associations showed one_to_many and one_to_one associations,
|
|
434
575
|
it's just because those are the simplest examples. Sequel supports all of the same features for
|
|
@@ -436,29 +577,7 @@ many_to_many and one_through_one associations that are enabled by default, as we
|
|
|
436
577
|
many_through_many and one_through_many associations that are added by the many_through_many
|
|
437
578
|
plugin.
|
|
438
579
|
|
|
439
|
-
==
|
|
440
|
-
|
|
441
|
-
Sequel supports all of associations that ActiveRecord supports, though some
|
|
442
|
-
require different approaches or custom <tt>:eager_loader</tt> options.
|
|
443
|
-
|
|
444
|
-
=== Association callbacks
|
|
445
|
-
|
|
446
|
-
Sequel supports the same callbacks that ActiveRecord does for +one_to_many+ and
|
|
447
|
-
+many_to_many+ associations: <tt>:before_add</tt>, <tt>:before_remove</tt>, <tt>:after_add</tt>, and
|
|
448
|
-
<tt>:after_remove</tt>. For +many_to_one+ associations and +one_to_one+ associations, Sequel
|
|
449
|
-
supports the <tt>:before_set</tt> and <tt>:after_set</tt> callbacks. On all associations,
|
|
450
|
-
Sequel supports <tt>:after_load</tt>, which is called after the association has been
|
|
451
|
-
loaded.
|
|
452
|
-
|
|
453
|
-
Each of these options can be a symbol specifying an instance method
|
|
454
|
-
that takes one argument (the associated object), or a proc that takes
|
|
455
|
-
two arguments (the current object and the associated object), or an
|
|
456
|
-
array of symbols and procs. For <tt>:after_load</tt> with a *_to_many association,
|
|
457
|
-
the associated object argument is an array of associated objects.
|
|
458
|
-
|
|
459
|
-
If any of the before callbacks return +false+, the adding/removing
|
|
460
|
-
does not happen and it either raises a <tt>Sequel::HookFailed</tt> (the default), or
|
|
461
|
-
returns false (if +raise_on_save_failure+ is false).
|
|
580
|
+
== More advanced association examples
|
|
462
581
|
|
|
463
582
|
=== Association extensions
|
|
464
583
|
|
|
@@ -481,36 +600,21 @@ the model object that created the association dataset via the dataset's
|
|
|
481
600
|
end
|
|
482
601
|
end
|
|
483
602
|
class Author < Sequel::Model
|
|
484
|
-
one_to_many :authorships, :
|
|
485
|
-
end
|
|
486
|
-
Author.first.authorships_dataset.find_or_create(:name=>'Blah', :number=>10)
|
|
487
|
-
|
|
488
|
-
=== <tt>has_many :through</tt> associations
|
|
489
|
-
|
|
490
|
-
+many_to_many+ handles the usual case of a <tt>has_many :through</tt> with a +belongs_to+ in
|
|
491
|
-
the associated model. It doesn't break on the case where the join table is a
|
|
492
|
-
model table, unlike ActiveRecord's +has_and_belongs_to_many+.
|
|
493
|
-
|
|
494
|
-
ActiveRecord:
|
|
495
|
-
|
|
496
|
-
class Author < ActiveRecord::Base
|
|
497
|
-
has_many :authorships
|
|
498
|
-
has_many :books, :through => :authorships
|
|
603
|
+
one_to_many :authorships, extend: FindOrCreate
|
|
499
604
|
end
|
|
605
|
+
Author.first.authorships_dataset.find_or_create(name: 'Blah', number: 10)
|
|
500
606
|
|
|
501
|
-
|
|
502
|
-
belongs_to :author
|
|
503
|
-
belongs_to :book
|
|
504
|
-
end
|
|
607
|
+
=== many_to_many associations through model tables
|
|
505
608
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
609
|
+
The many_to_many association can be used even when the join table is a table used for a
|
|
610
|
+
model. The only requirement is the join table has foreign keys to both the current
|
|
611
|
+
model and the associated model. Anytime there is a one_to_many association from model A to
|
|
612
|
+
model B, and model B has a many_to_one association to model C, you can use a many_to_many
|
|
613
|
+
association from model A to model C.
|
|
510
614
|
|
|
511
615
|
class Author < Sequel::Model
|
|
512
616
|
one_to_many :authorships
|
|
513
|
-
many_to_many :books, :
|
|
617
|
+
many_to_many :books, join_table: :authorships
|
|
514
618
|
end
|
|
515
619
|
|
|
516
620
|
class Authorship < Sequel::Model
|
|
@@ -521,33 +625,17 @@ Sequel::Model:
|
|
|
521
625
|
@author = Author.first
|
|
522
626
|
@author.books
|
|
523
627
|
|
|
524
|
-
|
|
525
|
-
you still use a +many_to_many+ association, but you need to use some options:
|
|
628
|
+
=== many_to_many for three-level associations
|
|
526
629
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
class Client < ActiveRecord::Base
|
|
535
|
-
belongs_to :firm
|
|
536
|
-
has_many :invoices
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
class Invoice < ActiveRecord::Base
|
|
540
|
-
belongs_to :client
|
|
541
|
-
has_one :firm, :through => :client
|
|
542
|
-
end
|
|
543
|
-
|
|
544
|
-
Firm.find(:first).invoices
|
|
545
|
-
|
|
546
|
-
Sequel::Model:
|
|
630
|
+
You can even use a many_to_many association between model A and model C if model A has a
|
|
631
|
+
one_to_many association to model B, and model B has a one_to_many association to model C.
|
|
632
|
+
You just need to use the appropriate :right_key and :right_primary_key options. And in
|
|
633
|
+
the reverse direction from model C to model A, you can use a one_through_one association
|
|
634
|
+
using the :left_key and :left_primary_key options.
|
|
547
635
|
|
|
548
636
|
class Firm < Sequel::Model
|
|
549
637
|
one_to_many :clients
|
|
550
|
-
many_to_many :invoices, :
|
|
638
|
+
many_to_many :invoices, join_table: :clients, right_key: :id, right_primary_key: :client_id
|
|
551
639
|
end
|
|
552
640
|
|
|
553
641
|
class Client < Sequel::Model
|
|
@@ -557,12 +645,13 @@ Sequel::Model:
|
|
|
557
645
|
|
|
558
646
|
class Invoice < Sequel::Model
|
|
559
647
|
many_to_one :client
|
|
560
|
-
one_through_one :firm, :
|
|
648
|
+
one_through_one :firm, join_table: :clients, left_key: :id, left_primary_key: :client_id
|
|
561
649
|
end
|
|
562
650
|
|
|
563
651
|
Firm.first.invoices
|
|
652
|
+
Invoice.first.firm
|
|
564
653
|
|
|
565
|
-
To handle cases where there are multiple join tables, use the many_through_many
|
|
654
|
+
To handle cases where there are multiple join tables, you can use the many_through_many
|
|
566
655
|
plugin that ships with Sequel.
|
|
567
656
|
|
|
568
657
|
=== Polymorphic Associations
|
|
@@ -579,38 +668,19 @@ you are stuck with an existing design that uses them.
|
|
|
579
668
|
If you must use them, look for the sequel_polymorphic external plugin, as it makes using
|
|
580
669
|
polymorphic associations in Sequel about as easy as it is in ActiveRecord. However,
|
|
581
670
|
here's how they can be done using Sequel's custom associations (the sequel_polymorphic
|
|
582
|
-
plugin is just a generic version of this code):
|
|
583
|
-
|
|
584
|
-
ActiveRecord:
|
|
585
|
-
|
|
586
|
-
class Asset < ActiveRecord::Base
|
|
587
|
-
belongs_to :attachable, :polymorphic => true
|
|
588
|
-
end
|
|
589
|
-
|
|
590
|
-
class Post < ActiveRecord::Base
|
|
591
|
-
has_many :assets, :as => :attachable
|
|
592
|
-
end
|
|
593
|
-
|
|
594
|
-
class Note < ActiveRecord::Base
|
|
595
|
-
has_many :assets, :as => :attachable
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
@asset.attachable = @post
|
|
599
|
-
@asset.attachable = @note
|
|
600
|
-
|
|
601
|
-
Sequel::Model:
|
|
671
|
+
external plugin is just a generic version of this code):
|
|
602
672
|
|
|
603
673
|
class Asset < Sequel::Model
|
|
604
|
-
many_to_one :attachable, :
|
|
605
|
-
:
|
|
674
|
+
many_to_one :attachable, reciprocal: :assets,
|
|
675
|
+
setter: (lambda do |attachable|
|
|
606
676
|
self[:attachable_id] = (attachable.pk if attachable)
|
|
607
677
|
self[:attachable_type] = (attachable.class.name if attachable)
|
|
608
678
|
end),
|
|
609
|
-
:
|
|
679
|
+
dataset: (proc do
|
|
610
680
|
klass = attachable_type.constantize
|
|
611
681
|
klass.where(klass.primary_key=>attachable_id)
|
|
612
682
|
end),
|
|
613
|
-
:
|
|
683
|
+
eager_loader: (lambda do |eo|
|
|
614
684
|
id_map = {}
|
|
615
685
|
eo[:rows].each do |asset|
|
|
616
686
|
asset.associations[:attachable] = nil
|
|
@@ -628,24 +698,22 @@ Sequel::Model:
|
|
|
628
698
|
end
|
|
629
699
|
|
|
630
700
|
class Post < Sequel::Model
|
|
631
|
-
one_to_many :assets, :
|
|
632
|
-
:
|
|
633
|
-
:
|
|
634
|
-
:
|
|
701
|
+
one_to_many :assets, key: :attachable_id, reciprocal: :attachable, conditions: {attachable_type: 'Post'},
|
|
702
|
+
adder: lambda{|asset| asset.update(attachable_id: pk, attachable_type: 'Post')},
|
|
703
|
+
remover: lambda{|asset| asset.update(attachable_id: nil, attachable_type: nil)},
|
|
704
|
+
clearer: lambda{assets_dataset.update(attachable_id: nil, attachable_type: nil)}
|
|
635
705
|
end
|
|
636
706
|
|
|
637
707
|
class Note < Sequel::Model
|
|
638
|
-
one_to_many :assets, :
|
|
639
|
-
:
|
|
640
|
-
:
|
|
641
|
-
:
|
|
708
|
+
one_to_many :assets, key: :attachable_id, reciprocal: :attachable, conditions: {attachable_type: 'Note'},
|
|
709
|
+
adder: lambda{|asset| asset.update(attachable_id: pk, attachable_type: 'Note')},
|
|
710
|
+
remover: lambda{|asset| asset.update(attachable_id: nil, attachable_type: nil)},
|
|
711
|
+
clearer: lambda{assets_dataset.update(attachable_id: nil, attachable_type: nil)}
|
|
642
712
|
end
|
|
643
713
|
|
|
644
714
|
@asset.attachable = @post
|
|
645
715
|
@asset.attachable = @note
|
|
646
716
|
|
|
647
|
-
== Other advanced associations
|
|
648
|
-
|
|
649
717
|
=== Joining on multiple keys
|
|
650
718
|
|
|
651
719
|
Let's say you have two tables that are associated with each other with multiple
|
|
@@ -657,36 +725,36 @@ associations:
|
|
|
657
725
|
# associated favorite track
|
|
658
726
|
|
|
659
727
|
class Track < Sequel::Model
|
|
660
|
-
many_to_one :favorite_track, :
|
|
728
|
+
many_to_one :favorite_track, key: [:disc_number, :number, :album_id], primary_key: [:disc_number, :number, :album_id]
|
|
661
729
|
end
|
|
662
730
|
class FavoriteTrack < Sequel::Model
|
|
663
|
-
one_to_one :tracks, :
|
|
731
|
+
one_to_one :tracks, key: [:disc_number, :number, :album_id], primary_key: [:disc_number, :number, :album_id]
|
|
664
732
|
end
|
|
665
733
|
|
|
666
|
-
=== Tree - All Ancestors and
|
|
734
|
+
=== Tree - All Ancestors and Descendants
|
|
667
735
|
|
|
668
736
|
Let's say you want to store a tree relationship in your database, it's pretty
|
|
669
737
|
simple:
|
|
670
738
|
|
|
671
739
|
class Node < Sequel::Model
|
|
672
|
-
many_to_one :parent, :
|
|
673
|
-
one_to_many :children, :
|
|
740
|
+
many_to_one :parent, class: self
|
|
741
|
+
one_to_many :children, key: :parent_id, class: self
|
|
674
742
|
end
|
|
675
743
|
|
|
676
744
|
You can easily get a node's parent with node.parent, and a node's children with
|
|
677
745
|
node.children. You can even eager load the relationship up to a certain depth:
|
|
678
746
|
|
|
679
747
|
# Eager load three generations of generations of children for a given node
|
|
680
|
-
Node.
|
|
748
|
+
Node.where(id: 1).eager(children: {children: :children}).all.first
|
|
681
749
|
# Load parents and grandparents for a group of nodes
|
|
682
|
-
Node.
|
|
750
|
+
Node.where{id < 10}.eager(parent: :parent).all
|
|
683
751
|
|
|
684
|
-
What if you want to get all ancestors up to the root node, or all
|
|
752
|
+
What if you want to get all ancestors up to the root node, or all descendants,
|
|
685
753
|
without knowing the depth of the tree?
|
|
686
754
|
|
|
687
755
|
class Node < Sequel::Model
|
|
688
|
-
many_to_one :ancestors, :
|
|
689
|
-
:
|
|
756
|
+
many_to_one :ancestors, class: self,
|
|
757
|
+
eager_loader: (lambda do |eo|
|
|
690
758
|
# Handle cases where the root node has the same parent_id as primary_key
|
|
691
759
|
# and also when it is NULL
|
|
692
760
|
non_root_nodes = eo[:rows].reject do |n|
|
|
@@ -702,15 +770,15 @@ without knowing the depth of the tree?
|
|
|
702
770
|
id_map = {}
|
|
703
771
|
# Create an map of parent_ids to nodes that have that parent id
|
|
704
772
|
non_root_nodes.each{|n| (id_map[n.parent_id] ||= []) << n}
|
|
705
|
-
# Doesn't cause an
|
|
773
|
+
# Doesn't cause an infinite loop, because when only the root node
|
|
706
774
|
# is left, this is not called.
|
|
707
|
-
Node.where(
|
|
775
|
+
Node.where(id: id_map.keys).eager(:ancestors).all do |node|
|
|
708
776
|
# Populate the parent association for each node
|
|
709
777
|
id_map[node.pk].each{|n| n.associations[:parent] = node}
|
|
710
778
|
end
|
|
711
779
|
end
|
|
712
780
|
end)
|
|
713
|
-
many_to_one :descendants, :
|
|
781
|
+
many_to_one :descendants, eager_loader: (lambda do |eo|
|
|
714
782
|
id_map = {}
|
|
715
783
|
eo[:rows].each do |n|
|
|
716
784
|
# Initialize an empty array of child associations for each parent node
|
|
@@ -722,7 +790,7 @@ without knowing the depth of the tree?
|
|
|
722
790
|
# if no records are returned. Exclude id = parent_id to avoid infinite loop
|
|
723
791
|
# if the root note is one of the returned records and it has parent_id = id
|
|
724
792
|
# instead of parent_id = NULL.
|
|
725
|
-
Node.where(:
|
|
793
|
+
Node.where(parent_id: id_map.keys).exclude(id: :parent_id).eager(:descendants).all do |node|
|
|
726
794
|
# Get the parent from the identity map
|
|
727
795
|
parent = id_map[node.parent_id]
|
|
728
796
|
# Set the child's parent association to the parent
|
|
@@ -733,11 +801,7 @@ without knowing the depth of the tree?
|
|
|
733
801
|
end)
|
|
734
802
|
end
|
|
735
803
|
|
|
736
|
-
Note that
|
|
737
|
-
The results are not the same as in the above case, as all descendents are stored in a single association,
|
|
738
|
-
but all descendants can be both lazy loaded or eager loaded in a single query (assuming your database
|
|
739
|
-
supports recursive common table expressions). Sequel ships with an +rcte_tree+ plugin that makes
|
|
740
|
-
this easy:
|
|
804
|
+
Note that Sequel ships with an rcte_tree plugin that does all of the above and more:
|
|
741
805
|
|
|
742
806
|
class Node < Sequel::Model
|
|
743
807
|
plugin :rcte_tree
|
|
@@ -757,21 +821,21 @@ What you want to do is get all songs for a given artist, ordered by the song's
|
|
|
757
821
|
name, with no duplicates?
|
|
758
822
|
|
|
759
823
|
class Artist < Sequel::Model
|
|
760
|
-
one_to_many :songs, :
|
|
761
|
-
:
|
|
762
|
-
:
|
|
824
|
+
one_to_many :songs, order: Sequel[:songs][:name],
|
|
825
|
+
dataset: proc{Song.select_all(:songs).join(:lyrics, id: :lyric_id, id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])},
|
|
826
|
+
eager_loader: (lambda do |eo|
|
|
763
827
|
h = eo[:id_map]
|
|
764
828
|
ids = h.keys
|
|
765
829
|
eo[:rows].each{|r| r.associations[:songs] = []}
|
|
766
830
|
Song.select_all(:songs).
|
|
767
|
-
select_append
|
|
768
|
-
join(
|
|
769
|
-
order
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
831
|
+
select_append{[lyrics[:composer_id], lyrics[:arranger_id], lyrics[:vocalist_id], lyrics[:lyricist_id]]}.
|
|
832
|
+
join(:lyrics, id: :lyric_id){Sequel.or(composer_id: ids, arranger_id: ids, vocalist_id: ids, lyricist_id: ids)}.
|
|
833
|
+
order{songs[:name]}.all do |song|
|
|
834
|
+
[:composer_id, :arranger_id, :vocalist_id, :lyricist_id].each do |x|
|
|
835
|
+
recs = h[song.values.delete(x)]
|
|
836
|
+
recs.each{|r| r.associations[:songs] << song} if recs
|
|
837
|
+
end
|
|
773
838
|
end
|
|
774
|
-
end
|
|
775
839
|
eo[:rows].each{|r| r.associations[:songs].uniq!}
|
|
776
840
|
end)
|
|
777
841
|
end
|
|
@@ -788,11 +852,11 @@ associated tickets.
|
|
|
788
852
|
|
|
789
853
|
class Project < Sequel::Model
|
|
790
854
|
one_to_many :tickets
|
|
791
|
-
many_to_one :ticket_hours, :
|
|
792
|
-
:
|
|
793
|
-
:
|
|
855
|
+
many_to_one :ticket_hours, read_only: true, key: :id,
|
|
856
|
+
dataset: proc{Ticket.where(:project_id=>id).select{sum(hours).as(hours)}},
|
|
857
|
+
eager_loader: (lambda do |eo|
|
|
794
858
|
eo[:rows].each{|p| p.associations[:ticket_hours] = nil}
|
|
795
|
-
Ticket.where(:
|
|
859
|
+
Ticket.where(project_id: eo[:id_map].keys).
|
|
796
860
|
select_group(:project_id).
|
|
797
861
|
select_append{sum(hours).as(hours)}.
|
|
798
862
|
all do |t|
|
|
@@ -815,4 +879,4 @@ associated tickets.
|
|
|
815
879
|
end
|
|
816
880
|
|
|
817
881
|
Note that it is often better to use a sum cache instead of this approach. You can implement
|
|
818
|
-
a sum cache using +after_create+ and +after_delete+ hooks, or
|
|
882
|
+
a sum cache using +after_create+, +after_update+, and +after_delete+ hooks, or preferably using a database trigger.
|