sequel 5.8.0 → 5.38.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 +4 -4
- data/CHANGELOG +409 -1795
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/bin/sequel +4 -0
- data/doc/advanced_associations.rdoc +136 -18
- data/doc/association_basics.rdoc +10 -5
- data/doc/cheat_sheet.rdoc +1 -0
- data/doc/code_order.rdoc +12 -2
- data/doc/dataset_filtering.rdoc +17 -2
- data/doc/mass_assignment.rdoc +3 -3
- data/doc/model_dataset_method_design.rdoc +1 -1
- data/doc/model_plugins.rdoc +1 -1
- data/doc/opening_databases.rdoc +30 -8
- data/doc/postgresql.rdoc +107 -2
- 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.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.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.38.0.txt +28 -0
- data/doc/release_notes/5.9.0.txt +99 -0
- data/doc/security.rdoc +10 -0
- data/doc/sharding.rdoc +42 -28
- data/doc/sql.rdoc +12 -0
- data/doc/testing.rdoc +24 -17
- data/doc/transactions.rdoc +78 -0
- data/doc/validations.rdoc +2 -2
- data/lib/sequel/adapters/ado.rb +26 -18
- data/lib/sequel/adapters/ado/access.rb +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +5 -8
- data/lib/sequel/adapters/amalgalite.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +71 -27
- data/lib/sequel/adapters/jdbc/mysql.rb +6 -6
- data/lib/sequel/adapters/jdbc/oracle.rb +7 -6
- data/lib/sequel/adapters/jdbc/postgresql.rb +17 -28
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +5 -6
- data/lib/sequel/adapters/jdbc/sqlite.rb +33 -2
- data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -3
- data/lib/sequel/adapters/jdbc/transactions.rb +14 -28
- data/lib/sequel/adapters/mysql.rb +14 -15
- data/lib/sequel/adapters/mysql2.rb +5 -3
- data/lib/sequel/adapters/odbc.rb +4 -6
- data/lib/sequel/adapters/oracle.rb +7 -7
- data/lib/sequel/adapters/postgres.rb +52 -16
- data/lib/sequel/adapters/shared/access.rb +16 -12
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +41 -18
- data/lib/sequel/adapters/shared/mysql.rb +66 -19
- data/lib/sequel/adapters/shared/oracle.rb +29 -23
- data/lib/sequel/adapters/shared/postgres.rb +341 -95
- data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
- data/lib/sequel/adapters/shared/sqlite.rb +174 -21
- data/lib/sequel/adapters/sqlanywhere.rb +33 -17
- data/lib/sequel/adapters/sqlite.rb +78 -68
- data/lib/sequel/adapters/tinytds.rb +14 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +2 -5
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +5 -1
- data/lib/sequel/connection_pool.rb +2 -6
- data/lib/sequel/connection_pool/sharded_single.rb +7 -4
- data/lib/sequel/connection_pool/sharded_threaded.rb +32 -21
- data/lib/sequel/connection_pool/single.rb +1 -1
- data/lib/sequel/connection_pool/threaded.rb +26 -11
- data/lib/sequel/core.rb +327 -319
- data/lib/sequel/database/connecting.rb +7 -8
- data/lib/sequel/database/logging.rb +7 -1
- data/lib/sequel/database/misc.rb +68 -34
- data/lib/sequel/database/query.rb +6 -4
- data/lib/sequel/database/schema_generator.rb +31 -11
- data/lib/sequel/database/schema_methods.rb +32 -22
- data/lib/sequel/database/transactions.rb +129 -25
- data/lib/sequel/dataset.rb +4 -2
- data/lib/sequel/dataset/actions.rb +34 -23
- data/lib/sequel/dataset/features.rb +34 -0
- data/lib/sequel/dataset/graph.rb +27 -11
- data/lib/sequel/dataset/misc.rb +17 -3
- data/lib/sequel/dataset/placeholder_literalizer.rb +50 -21
- data/lib/sequel/dataset/prepared_statements.rb +96 -26
- data/lib/sequel/dataset/query.rb +43 -8
- data/lib/sequel/dataset/sql.rb +189 -41
- data/lib/sequel/deprecated.rb +3 -1
- data/lib/sequel/exceptions.rb +2 -0
- data/lib/sequel/extensions/_pretty_table.rb +1 -2
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/columns_introspection.rb +1 -2
- data/lib/sequel/extensions/connection_expiration.rb +6 -6
- data/lib/sequel/extensions/connection_validator.rb +7 -6
- data/lib/sequel/extensions/constant_sql_override.rb +65 -0
- data/lib/sequel/extensions/constraint_validations.rb +53 -28
- data/lib/sequel/extensions/core_refinements.rb +2 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +3 -1
- data/lib/sequel/extensions/exclude_or_null.rb +68 -0
- data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
- data/lib/sequel/extensions/index_caching.rb +9 -7
- data/lib/sequel/extensions/integer64.rb +3 -1
- data/lib/sequel/extensions/looser_typecasting.rb +3 -3
- data/lib/sequel/extensions/migration.rb +13 -6
- data/lib/sequel/extensions/named_timezones.rb +84 -23
- data/lib/sequel/extensions/pg_array.rb +87 -79
- data/lib/sequel/extensions/pg_array_ops.rb +14 -6
- data/lib/sequel/extensions/pg_enum.rb +34 -18
- data/lib/sequel/extensions/pg_extended_date_support.rb +34 -14
- data/lib/sequel/extensions/pg_hstore.rb +6 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +15 -5
- data/lib/sequel/extensions/pg_interval.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +387 -123
- data/lib/sequel/extensions/pg_json_ops.rb +168 -0
- data/lib/sequel/extensions/pg_range.rb +20 -10
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +3 -2
- data/lib/sequel/extensions/pg_row_ops.rb +24 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
- data/lib/sequel/extensions/query.rb +1 -0
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +13 -7
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +4 -2
- data/lib/sequel/extensions/server_block.rb +18 -7
- data/lib/sequel/extensions/sql_comments.rb +2 -2
- data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +9 -3
- data/lib/sequel/model.rb +3 -1
- data/lib/sequel/model/associations.rb +403 -69
- data/lib/sequel/model/base.rb +170 -90
- data/lib/sequel/model/plugins.rb +105 -0
- data/lib/sequel/plugins/after_initialize.rb +1 -1
- data/lib/sequel/plugins/association_dependencies.rb +3 -3
- 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 +74 -22
- data/lib/sequel/plugins/association_proxies.rb +6 -2
- data/lib/sequel/plugins/auto_validations.rb +36 -17
- data/lib/sequel/plugins/blacklist_security.rb +1 -2
- data/lib/sequel/plugins/boolean_subsets.rb +4 -1
- data/lib/sequel/plugins/caching.rb +3 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +62 -34
- data/lib/sequel/plugins/composition.rb +13 -9
- data/lib/sequel/plugins/csv_serializer.rb +28 -9
- data/lib/sequel/plugins/defaults_setter.rb +2 -2
- data/lib/sequel/plugins/dirty.rb +60 -22
- data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
- data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
- data/lib/sequel/plugins/finder.rb +2 -2
- data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
- data/lib/sequel/plugins/hook_class_methods.rb +17 -5
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/inverted_subsets.rb +2 -2
- data/lib/sequel/plugins/json_serializer.rb +21 -14
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/list.rb +22 -10
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +27 -5
- data/lib/sequel/plugins/pg_array_associations.rb +12 -9
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +149 -61
- data/lib/sequel/plugins/prepared_statements.rb +6 -12
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
- data/lib/sequel/plugins/rcte_tree.rb +20 -22
- data/lib/sequel/plugins/sharding.rb +13 -7
- data/lib/sequel/plugins/single_table_inheritance.rb +20 -15
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/static_cache.rb +36 -17
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +1 -1
- data/lib/sequel/plugins/subclasses.rb +2 -0
- data/lib/sequel/plugins/subset_conditions.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +73 -2
- data/lib/sequel/plugins/throw_failures.rb +110 -0
- data/lib/sequel/plugins/tree.rb +49 -31
- data/lib/sequel/plugins/typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/validation_class_methods.rb +11 -5
- data/lib/sequel/plugins/validation_helpers.rb +2 -2
- data/lib/sequel/sql.rb +120 -30
- data/lib/sequel/timezones.rb +55 -14
- data/lib/sequel/version.rb +6 -1
- metadata +101 -361
- data/Rakefile +0 -151
- 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.27.0.txt +0 -78
- data/doc/release_notes/4.28.0.txt +0 -57
- data/doc/release_notes/4.29.0.txt +0 -41
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.30.0.txt +0 -37
- data/doc/release_notes/4.31.0.txt +0 -57
- data/doc/release_notes/4.32.0.txt +0 -132
- data/doc/release_notes/4.33.0.txt +0 -88
- data/doc/release_notes/4.34.0.txt +0 -86
- data/doc/release_notes/4.35.0.txt +0 -130
- data/doc/release_notes/4.36.0.txt +0 -116
- data/doc/release_notes/4.37.0.txt +0 -50
- data/doc/release_notes/4.38.0.txt +0 -67
- data/doc/release_notes/4.39.0.txt +0 -127
- data/doc/release_notes/4.4.0.txt +0 -92
- data/doc/release_notes/4.40.0.txt +0 -179
- data/doc/release_notes/4.41.0.txt +0 -77
- data/doc/release_notes/4.42.0.txt +0 -221
- data/doc/release_notes/4.43.0.txt +0 -87
- data/doc/release_notes/4.44.0.txt +0 -125
- data/doc/release_notes/4.45.0.txt +0 -370
- data/doc/release_notes/4.46.0.txt +0 -404
- data/doc/release_notes/4.47.0.txt +0 -56
- data/doc/release_notes/4.48.0.txt +0 -293
- data/doc/release_notes/4.49.0.txt +0 -222
- 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/spec/adapter_spec.rb +0 -4
- data/spec/adapters/db2_spec.rb +0 -170
- data/spec/adapters/mssql_spec.rb +0 -804
- data/spec/adapters/mysql_spec.rb +0 -1041
- data/spec/adapters/oracle_spec.rb +0 -327
- data/spec/adapters/postgres_spec.rb +0 -4000
- data/spec/adapters/spec_helper.rb +0 -43
- data/spec/adapters/sqlanywhere_spec.rb +0 -97
- data/spec/adapters/sqlite_spec.rb +0 -600
- data/spec/bin_spec.rb +0 -269
- data/spec/core/connection_pool_spec.rb +0 -1228
- data/spec/core/database_spec.rb +0 -2673
- data/spec/core/dataset_spec.rb +0 -5419
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1344
- data/spec/core/mock_adapter_spec.rb +0 -722
- data/spec/core/object_graph_spec.rb +0 -306
- data/spec/core/placeholder_literalizer_spec.rb +0 -166
- data/spec/core/schema_generator_spec.rb +0 -214
- data/spec/core/schema_spec.rb +0 -1820
- data/spec/core/spec_helper.rb +0 -23
- data/spec/core/version_spec.rb +0 -7
- data/spec/core_extensions_spec.rb +0 -762
- data/spec/core_model_spec.rb +0 -2
- data/spec/core_spec.rb +0 -1
- data/spec/deprecation_helper.rb +0 -30
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -99
- 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 -125
- data/spec/extensions/association_pks_spec.rb +0 -423
- data/spec/extensions/association_proxies_spec.rb +0 -100
- data/spec/extensions/auto_literal_strings_spec.rb +0 -205
- data/spec/extensions/auto_validations_spec.rb +0 -202
- data/spec/extensions/blacklist_security_spec.rb +0 -95
- data/spec/extensions/blank_spec.rb +0 -69
- data/spec/extensions/boolean_readers_spec.rb +0 -93
- data/spec/extensions/boolean_subsets_spec.rb +0 -47
- data/spec/extensions/caching_spec.rb +0 -273
- data/spec/extensions/class_table_inheritance_spec.rb +0 -568
- data/spec/extensions/column_conflicts_spec.rb +0 -75
- data/spec/extensions/column_select_spec.rb +0 -129
- data/spec/extensions/columns_introspection_spec.rb +0 -90
- data/spec/extensions/columns_updated_spec.rb +0 -35
- data/spec/extensions/composition_spec.rb +0 -248
- data/spec/extensions/connection_expiration_spec.rb +0 -133
- data/spec/extensions/connection_validator_spec.rb +0 -127
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
- data/spec/extensions/constraint_validations_spec.rb +0 -395
- data/spec/extensions/core_refinements_spec.rb +0 -528
- data/spec/extensions/csv_serializer_spec.rb +0 -183
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -365
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -181
- data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
- data/spec/extensions/def_dataset_method_spec.rb +0 -100
- data/spec/extensions/defaults_setter_spec.rb +0 -141
- data/spec/extensions/delay_add_association_spec.rb +0 -73
- data/spec/extensions/dirty_spec.rb +0 -189
- data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
- data/spec/extensions/eager_each_spec.rb +0 -62
- 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 -74
- data/spec/extensions/finder_spec.rb +0 -260
- data/spec/extensions/force_encoding_spec.rb +0 -126
- data/spec/extensions/freeze_datasets_spec.rb +0 -31
- data/spec/extensions/graph_each_spec.rb +0 -113
- data/spec/extensions/hook_class_methods_spec.rb +0 -380
- data/spec/extensions/identifier_mangling_spec.rb +0 -201
- data/spec/extensions/implicit_subquery_spec.rb +0 -58
- data/spec/extensions/index_caching_spec.rb +0 -66
- data/spec/extensions/inflector_spec.rb +0 -183
- data/spec/extensions/input_transformer_spec.rb +0 -69
- data/spec/extensions/insert_returning_select_spec.rb +0 -72
- data/spec/extensions/instance_filters_spec.rb +0 -79
- data/spec/extensions/instance_hooks_spec.rb +0 -246
- data/spec/extensions/integer64_spec.rb +0 -22
- data/spec/extensions/inverted_subsets_spec.rb +0 -33
- data/spec/extensions/json_serializer_spec.rb +0 -336
- data/spec/extensions/lazy_attributes_spec.rb +0 -183
- data/spec/extensions/list_spec.rb +0 -275
- data/spec/extensions/looser_typecasting_spec.rb +0 -43
- data/spec/extensions/many_through_many_spec.rb +0 -2177
- data/spec/extensions/migration_spec.rb +0 -840
- data/spec/extensions/modification_detection_spec.rb +0 -93
- data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -92
- data/spec/extensions/named_timezones_spec.rb +0 -109
- data/spec/extensions/nested_attributes_spec.rb +0 -703
- data/spec/extensions/null_dataset_spec.rb +0 -85
- data/spec/extensions/optimistic_locking_spec.rb +0 -127
- data/spec/extensions/pagination_spec.rb +0 -116
- data/spec/extensions/pg_array_associations_spec.rb +0 -802
- data/spec/extensions/pg_array_ops_spec.rb +0 -144
- data/spec/extensions/pg_array_spec.rb +0 -398
- data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -165
- data/spec/extensions/pg_enum_spec.rb +0 -113
- data/spec/extensions/pg_extended_date_support_spec.rb +0 -126
- data/spec/extensions/pg_hstore_ops_spec.rb +0 -238
- data/spec/extensions/pg_hstore_spec.rb +0 -219
- data/spec/extensions/pg_inet_ops_spec.rb +0 -102
- data/spec/extensions/pg_inet_spec.rb +0 -72
- data/spec/extensions/pg_interval_spec.rb +0 -103
- data/spec/extensions/pg_json_ops_spec.rb +0 -289
- data/spec/extensions/pg_json_spec.rb +0 -262
- data/spec/extensions/pg_loose_count_spec.rb +0 -23
- data/spec/extensions/pg_range_ops_spec.rb +0 -60
- data/spec/extensions/pg_range_spec.rb +0 -487
- data/spec/extensions/pg_row_ops_spec.rb +0 -61
- data/spec/extensions/pg_row_plugin_spec.rb +0 -60
- data/spec/extensions/pg_row_spec.rb +0 -363
- data/spec/extensions/pg_static_cache_updater_spec.rb +0 -93
- data/spec/extensions/pg_timestamptz_spec.rb +0 -17
- data/spec/extensions/prepared_statements_safe_spec.rb +0 -66
- data/spec/extensions/prepared_statements_spec.rb +0 -182
- data/spec/extensions/pretty_table_spec.rb +0 -123
- data/spec/extensions/query_spec.rb +0 -94
- data/spec/extensions/rcte_tree_spec.rb +0 -381
- data/spec/extensions/round_timestamps_spec.rb +0 -39
- data/spec/extensions/s_spec.rb +0 -60
- data/spec/extensions/schema_caching_spec.rb +0 -64
- data/spec/extensions/schema_dumper_spec.rb +0 -868
- data/spec/extensions/select_remove_spec.rb +0 -38
- data/spec/extensions/sequel_4_dataset_methods_spec.rb +0 -121
- data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
- data/spec/extensions/serialization_spec.rb +0 -365
- data/spec/extensions/server_block_spec.rb +0 -97
- data/spec/extensions/server_logging_spec.rb +0 -45
- data/spec/extensions/sharding_spec.rb +0 -189
- data/spec/extensions/shared_caching_spec.rb +0 -151
- data/spec/extensions/single_table_inheritance_spec.rb +0 -347
- data/spec/extensions/singular_table_names_spec.rb +0 -22
- data/spec/extensions/skip_create_refresh_spec.rb +0 -18
- data/spec/extensions/spec_helper.rb +0 -61
- data/spec/extensions/split_array_nil_spec.rb +0 -24
- data/spec/extensions/split_values_spec.rb +0 -57
- data/spec/extensions/sql_comments_spec.rb +0 -33
- data/spec/extensions/sql_expr_spec.rb +0 -59
- data/spec/extensions/static_cache_spec.rb +0 -410
- data/spec/extensions/string_agg_spec.rb +0 -90
- 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 -79
- data/spec/extensions/subset_conditions_spec.rb +0 -38
- data/spec/extensions/symbol_aref_refinement_spec.rb +0 -28
- data/spec/extensions/symbol_as_refinement_spec.rb +0 -21
- data/spec/extensions/synchronize_sql_spec.rb +0 -124
- data/spec/extensions/table_select_spec.rb +0 -83
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -141
- data/spec/extensions/thread_local_timezones_spec.rb +0 -67
- data/spec/extensions/timestamps_spec.rb +0 -209
- data/spec/extensions/to_dot_spec.rb +0 -153
- data/spec/extensions/touch_spec.rb +0 -226
- data/spec/extensions/tree_spec.rb +0 -284
- data/spec/extensions/typecast_on_load_spec.rb +0 -86
- data/spec/extensions/unlimited_update_spec.rb +0 -21
- data/spec/extensions/update_or_create_spec.rb +0 -83
- data/spec/extensions/update_primary_key_spec.rb +0 -105
- data/spec/extensions/update_refresh_spec.rb +0 -59
- data/spec/extensions/uuid_spec.rb +0 -101
- data/spec/extensions/validate_associated_spec.rb +0 -52
- data/spec/extensions/validation_class_methods_spec.rb +0 -1040
- data/spec/extensions/validation_contexts_spec.rb +0 -31
- data/spec/extensions/validation_helpers_spec.rb +0 -525
- data/spec/extensions/whitelist_security_spec.rb +0 -157
- data/spec/extensions/xml_serializer_spec.rb +0 -213
- 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/double_migration/001_create_sessions.rb +0 -9
- data/spec/files/double_migration/002_create_nodes.rb +0 -19
- data/spec/files/double_migration/003_3_create_users.rb +0 -4
- 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/empty_migration/001_create_sessions.rb +0 -9
- data/spec/files/empty_migration/002_create_nodes.rb +0 -0
- data/spec/files/empty_migration/003_3_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/reversible_migrations/006_reversible.rb +0 -10
- data/spec/files/reversible_migrations/007_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 -58
- data/spec/integration/associations_test.rb +0 -2513
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1880
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -262
- data/spec/integration/model_test.rb +0 -203
- data/spec/integration/plugin_test.rb +0 -2302
- data/spec/integration/prepared_statement_test.rb +0 -398
- data/spec/integration/schema_test.rb +0 -869
- data/spec/integration/spec_helper.rb +0 -64
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -354
- data/spec/integration/type_test.rb +0 -127
- data/spec/model/association_reflection_spec.rb +0 -803
- data/spec/model/associations_spec.rb +0 -4538
- data/spec/model/base_spec.rb +0 -817
- data/spec/model/class_dataset_methods_spec.rb +0 -146
- data/spec/model/dataset_methods_spec.rb +0 -198
- data/spec/model/eager_loading_spec.rb +0 -2262
- data/spec/model/hooks_spec.rb +0 -370
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -953
- data/spec/model/plugins_spec.rb +0 -318
- data/spec/model/record_spec.rb +0 -2107
- data/spec/model/spec_helper.rb +0 -45
- data/spec/model/validations_spec.rb +0 -193
- data/spec/model_no_assoc_spec.rb +0 -1
- data/spec/model_spec.rb +0 -1
- data/spec/plugin_spec.rb +0 -1
- data/spec/sequel_coverage.rb +0 -15
- data/spec/sequel_warning.rb +0 -4
- data/spec/spec_config.rb +0 -12
data/lib/sequel/extensions/s.rb
CHANGED
|
@@ -37,7 +37,7 @@ module Sequel
|
|
|
37
37
|
{:type =>schema[:type] == :boolean ? TrueClass : Integer}
|
|
38
38
|
when /\Abigint(?:\((?:\d+)\))?(?: unsigned)?\z/
|
|
39
39
|
{:type=>:Bignum}
|
|
40
|
-
when /\A(?:real|float|double(?: precision)?|double\(\d+,\d+\)(?: unsigned)
|
|
40
|
+
when /\A(?:real|float|double(?: precision)?|double\(\d+,\d+\))(?: unsigned)?\z/
|
|
41
41
|
{:type=>Float}
|
|
42
42
|
when 'boolean', 'bit', 'bool'
|
|
43
43
|
{:type=>TrueClass}
|
|
@@ -57,7 +57,7 @@ module Sequel
|
|
|
57
57
|
{:type=>String, :size=>($1.to_i if $1)}
|
|
58
58
|
when /\A(?:small)?money\z/
|
|
59
59
|
{:type=>BigDecimal, :size=>[19,2]}
|
|
60
|
-
when /\A(?:decimal|numeric|number)(?:\((\d+)(?:,\s*(\d+))?\))?\z/
|
|
60
|
+
when /\A(?:decimal|numeric|number)(?:\((\d+)(?:,\s*(\d+))?\))?(?: unsigned)?\z/
|
|
61
61
|
s = [($1.to_i if $1), ($2.to_i if $2)].compact
|
|
62
62
|
{:type=>BigDecimal, :size=>(s.empty? ? nil : s)}
|
|
63
63
|
when /\A(?:bytea|(?:tiny|medium|long)?blob|(?:var)?binary)(?:\((\d+)\))?\z/
|
|
@@ -199,12 +199,18 @@ END_MIG
|
|
|
199
199
|
end
|
|
200
200
|
type = col_opts.delete(:type)
|
|
201
201
|
col_opts.delete(:size) if col_opts[:size].nil?
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
if schema[:generated]
|
|
203
|
+
if options[:same_db] && database_type == :postgres
|
|
204
|
+
col_opts[:generated_always_as] = column_schema_to_ruby_default_fallback(schema[:default], options)
|
|
205
|
+
end
|
|
204
206
|
else
|
|
205
|
-
schema[:ruby_default]
|
|
207
|
+
col_opts[:default] = if schema[:ruby_default].nil?
|
|
208
|
+
column_schema_to_ruby_default_fallback(schema[:default], options)
|
|
209
|
+
else
|
|
210
|
+
schema[:ruby_default]
|
|
211
|
+
end
|
|
212
|
+
col_opts.delete(:default) if col_opts[:default].nil?
|
|
206
213
|
end
|
|
207
|
-
col_opts.delete(:default) if col_opts[:default].nil?
|
|
208
214
|
col_opts[:null] = false if schema[:allow_null] == false
|
|
209
215
|
if table = schema[:table]
|
|
210
216
|
[:key, :on_delete, :on_update, :deferrable].each{|f| col_opts[f] = schema[f] if schema[f]}
|
|
@@ -212,7 +218,7 @@ END_MIG
|
|
|
212
218
|
gen.foreign_key(name, table, col_opts)
|
|
213
219
|
else
|
|
214
220
|
gen.column(name, type, col_opts)
|
|
215
|
-
if [Integer, :Bignum, Float].include?(type) && schema[:db_type] =~ / unsigned\z/io
|
|
221
|
+
if [Integer, :Bignum, Float, BigDecimal].include?(type) && schema[:db_type] =~ / unsigned\z/io
|
|
216
222
|
gen.check(Sequel::SQL::Identifier.new(name) >= 0)
|
|
217
223
|
end
|
|
218
224
|
end
|
|
@@ -41,7 +41,8 @@ module Sequel
|
|
|
41
41
|
# # => 6
|
|
42
42
|
# DB[:table].interval{function(column)} # SELECT (max(function(column)) - min(function(column))) FROM table LIMIT 1
|
|
43
43
|
# # => 7
|
|
44
|
-
def interval(column=
|
|
44
|
+
def interval(column=(no_arg = true), &block)
|
|
45
|
+
column = Sequel.virtual_row(&block) if no_arg
|
|
45
46
|
if loader = cached_placeholder_literalizer(:_interval_loader) do |pl|
|
|
46
47
|
arg = pl.arg
|
|
47
48
|
aggregate_dataset.limit(1).select((SQL::Function.new(:max, arg) - SQL::Function.new(:min, arg)).as(:interval))
|
|
@@ -60,7 +61,8 @@ module Sequel
|
|
|
60
61
|
# # => 1..10
|
|
61
62
|
# DB[:table].interval{function(column)} # SELECT max(function(column)) AS v1, min(function(column)) AS v2 FROM table LIMIT 1
|
|
62
63
|
# # => 0..7
|
|
63
|
-
def range(column=
|
|
64
|
+
def range(column=(no_arg = true), &block)
|
|
65
|
+
column = Sequel.virtual_row(&block) if no_arg
|
|
64
66
|
r = if loader = cached_placeholder_literalizer(:_range_loader) do |pl|
|
|
65
67
|
arg = pl.arg
|
|
66
68
|
aggregate_dataset.limit(1).select(SQL::Function.new(:min, arg).as(:v1), SQL::Function.new(:max, arg).as(:v2))
|
|
@@ -52,6 +52,12 @@
|
|
|
52
52
|
# DB[:a].server(:read_only).delete # Uses shard2
|
|
53
53
|
# end
|
|
54
54
|
#
|
|
55
|
+
# If you use an invalid server when calling with_server, it will be
|
|
56
|
+
# treated the same way as if you called Dataset#server with an invalid
|
|
57
|
+
# server. By default, the default server will be used in such cases.
|
|
58
|
+
# If you would like a different server to be used, or an exception to
|
|
59
|
+
# be raised, then use the :servers_hash Database option.
|
|
60
|
+
#
|
|
55
61
|
# Related modules: Sequel::ServerBlock, Sequel::UnthreadedServerBlock,
|
|
56
62
|
# Sequel::ThreadedServerBlock
|
|
57
63
|
|
|
@@ -110,9 +116,9 @@ module Sequel
|
|
|
110
116
|
else
|
|
111
117
|
case server
|
|
112
118
|
when :default, nil
|
|
113
|
-
@default_servers[-1][0]
|
|
119
|
+
@servers[@default_servers[-1][0]]
|
|
114
120
|
when :read_only
|
|
115
|
-
@default_servers[-1][1]
|
|
121
|
+
@servers[@default_servers[-1][1]]
|
|
116
122
|
else
|
|
117
123
|
super
|
|
118
124
|
end
|
|
@@ -137,13 +143,13 @@ module Sequel
|
|
|
137
143
|
|
|
138
144
|
# Make the given server the new default server for the current thread.
|
|
139
145
|
def set_default_server(default_server, read_only_server=default_server)
|
|
140
|
-
sync{(@default_servers[
|
|
146
|
+
sync{(@default_servers[Sequel.current] ||= [])} << [default_server, read_only_server]
|
|
141
147
|
end
|
|
142
148
|
|
|
143
149
|
# Remove the current default server for the current thread, restoring the
|
|
144
150
|
# previous default server.
|
|
145
151
|
def clear_default_server
|
|
146
|
-
t =
|
|
152
|
+
t = Sequel.current
|
|
147
153
|
a = sync{@default_servers[t]}
|
|
148
154
|
a.pop
|
|
149
155
|
sync{@default_servers.delete(t)} if a.empty?
|
|
@@ -151,15 +157,20 @@ module Sequel
|
|
|
151
157
|
|
|
152
158
|
# Use the server given to with_server for the given thread, if appropriate.
|
|
153
159
|
def pick_server(server)
|
|
154
|
-
a = sync{@default_servers[
|
|
160
|
+
a = sync{@default_servers[Sequel.current]}
|
|
155
161
|
if !a || a.empty?
|
|
156
162
|
super
|
|
157
163
|
else
|
|
164
|
+
# Hash handling required to work when loaded after arbitrary servers plugin.
|
|
158
165
|
case server
|
|
159
166
|
when :default, nil
|
|
160
|
-
a[-1][0]
|
|
167
|
+
v = a[-1][0]
|
|
168
|
+
v = @servers[v] unless v.is_a?(Hash)
|
|
169
|
+
v
|
|
161
170
|
when :read_only
|
|
162
|
-
a[-1][1]
|
|
171
|
+
v = a[-1][1]
|
|
172
|
+
v = @servers[v] unless v.is_a?(Hash)
|
|
173
|
+
v
|
|
163
174
|
else
|
|
164
175
|
super
|
|
165
176
|
end
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
# #
|
|
10
10
|
#
|
|
11
11
|
# As you can see, this uses single line SQL comments (--) suffixed
|
|
12
|
-
# by a newline. This
|
|
13
|
-
#
|
|
12
|
+
# by a newline. This plugin transforms all consecutive whitespace
|
|
13
|
+
# in the comment to a single string:
|
|
14
14
|
#
|
|
15
15
|
# ds = DB[:table].comment("Some\r\nComment Here").all
|
|
16
16
|
# # SELECT * FROM table -- Some Comment Here
|
|
@@ -53,7 +53,13 @@ module Sequel
|
|
|
53
53
|
# is given, it is used directly as the node or transition. Otherwise
|
|
54
54
|
# a node is created for the current object.
|
|
55
55
|
def dot(label, j=nil)
|
|
56
|
-
|
|
56
|
+
label = case label
|
|
57
|
+
when nil
|
|
58
|
+
"<nil>"
|
|
59
|
+
else
|
|
60
|
+
label.to_s
|
|
61
|
+
end
|
|
62
|
+
@dot << "#{j||@i} [label=#{label.inspect}];"
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
# Recursive method that parses all of Sequel's internal datastructures,
|
|
@@ -61,7 +67,7 @@ module Sequel
|
|
|
61
67
|
# structure.
|
|
62
68
|
def v(e, l)
|
|
63
69
|
@i += 1
|
|
64
|
-
dot(l, "#{@stack.last} -> #{@i}")
|
|
70
|
+
dot(l, "#{@stack.last} -> #{@i}")
|
|
65
71
|
@stack.push(@i)
|
|
66
72
|
case e
|
|
67
73
|
when LiteralString
|
|
@@ -144,7 +150,7 @@ module Sequel
|
|
|
144
150
|
dot "Dataset"
|
|
145
151
|
TO_DOT_OPTIONS.each do |k|
|
|
146
152
|
if val = e.opts[k]
|
|
147
|
-
v(val, k
|
|
153
|
+
v(val, k)
|
|
148
154
|
end
|
|
149
155
|
end
|
|
150
156
|
else
|
data/lib/sequel/model.rb
CHANGED
|
@@ -69,7 +69,9 @@ module Sequel
|
|
|
69
69
|
require_relative "model/base"
|
|
70
70
|
require_relative "model/exceptions"
|
|
71
71
|
require_relative "model/errors"
|
|
72
|
+
# :nocov:
|
|
72
73
|
if !defined?(::SEQUEL_NO_ASSOCIATIONS) && !ENV.has_key?('SEQUEL_NO_ASSOCIATIONS')
|
|
74
|
+
# :nocov:
|
|
73
75
|
require_relative 'model/associations'
|
|
74
76
|
plugin Model::Associations
|
|
75
77
|
end
|
|
@@ -77,7 +79,7 @@ module Sequel
|
|
|
77
79
|
def_Model(::Sequel)
|
|
78
80
|
|
|
79
81
|
# The setter methods (methods ending with =) that are never allowed
|
|
80
|
-
# to be called automatically via +set+/+update+/+new+/etc
|
|
82
|
+
# to be called automatically via +set+/+update+/+new+/etc.
|
|
81
83
|
RESTRICTED_SETTER_METHODS = instance_methods.map(&:to_s).select{|l| l.end_with?('=')}.freeze
|
|
82
84
|
end
|
|
83
85
|
end
|
|
@@ -164,11 +164,11 @@ module Sequel
|
|
|
164
164
|
# range to return the object(s) at the correct offset/limit.
|
|
165
165
|
def apply_ruby_eager_limit_strategy(rows, limit_and_offset = limit_and_offset())
|
|
166
166
|
name = self[:name]
|
|
167
|
+
return unless range = slice_range(limit_and_offset)
|
|
167
168
|
if returns_array?
|
|
168
|
-
range = slice_range(limit_and_offset)
|
|
169
169
|
rows.each{|o| o.associations[name] = o.associations[name][range] || []}
|
|
170
|
-
|
|
171
|
-
offset =
|
|
170
|
+
else
|
|
171
|
+
offset = range.begin
|
|
172
172
|
rows.each{|o| o.associations[name] = o.associations[name][offset]}
|
|
173
173
|
end
|
|
174
174
|
end
|
|
@@ -356,7 +356,7 @@ module Sequel
|
|
|
356
356
|
def finalize
|
|
357
357
|
return unless cache = self[:cache]
|
|
358
358
|
|
|
359
|
-
|
|
359
|
+
finalizer = proc do |meth, key|
|
|
360
360
|
next if has_key?(key)
|
|
361
361
|
|
|
362
362
|
# Allow calling private methods to make sure caching is done appropriately
|
|
@@ -364,6 +364,13 @@ module Sequel
|
|
|
364
364
|
self[key] = cache.delete(key) if cache.has_key?(key)
|
|
365
365
|
end
|
|
366
366
|
|
|
367
|
+
finalize_settings.each(&finalizer)
|
|
368
|
+
|
|
369
|
+
unless self[:instance_specific]
|
|
370
|
+
finalizer.call(:associated_eager_dataset, :associated_eager_dataset)
|
|
371
|
+
finalizer.call(:filter_by_associations_conditions_dataset, :filter_by_associations_conditions_dataset)
|
|
372
|
+
end
|
|
373
|
+
|
|
367
374
|
nil
|
|
368
375
|
end
|
|
369
376
|
|
|
@@ -371,9 +378,7 @@ module Sequel
|
|
|
371
378
|
FINALIZE_SETTINGS = {
|
|
372
379
|
:associated_class=>:class,
|
|
373
380
|
:associated_dataset=>:_dataset,
|
|
374
|
-
:associated_eager_dataset=>:associated_eager_dataset,
|
|
375
381
|
:eager_limit_strategy=>:_eager_limit_strategy,
|
|
376
|
-
:filter_by_associations_conditions_dataset=>:filter_by_associations_conditions_dataset,
|
|
377
382
|
:placeholder_loader=>:placeholder_loader,
|
|
378
383
|
:predicate_key=>:predicate_key,
|
|
379
384
|
:predicate_keys=>:predicate_keys,
|
|
@@ -432,7 +437,11 @@ module Sequel
|
|
|
432
437
|
if use_placeholder_loader?
|
|
433
438
|
cached_fetch(:placeholder_loader) do
|
|
434
439
|
Sequel::Dataset::PlaceholderLiteralizer.loader(associated_dataset) do |pl, ds|
|
|
435
|
-
ds.where(Sequel.&(*predicate_keys.map{|k| SQL::BooleanExpression.new(:'=', k, pl.arg)}))
|
|
440
|
+
ds = ds.where(Sequel.&(*predicate_keys.map{|k| SQL::BooleanExpression.new(:'=', k, pl.arg)}))
|
|
441
|
+
if self[:block]
|
|
442
|
+
ds = self[:block].call(ds)
|
|
443
|
+
end
|
|
444
|
+
ds
|
|
436
445
|
end
|
|
437
446
|
end
|
|
438
447
|
end
|
|
@@ -633,10 +642,15 @@ module Sequel
|
|
|
633
642
|
ds = ds.eager(associations)
|
|
634
643
|
end
|
|
635
644
|
if block = eo[:eager_block]
|
|
645
|
+
orig_ds = ds
|
|
636
646
|
ds = block.call(ds)
|
|
637
647
|
end
|
|
638
648
|
if eager_loading_use_associated_key?
|
|
639
|
-
ds = ds.
|
|
649
|
+
ds = if ds.opts[:eager_graph] && !orig_ds.opts[:eager_graph]
|
|
650
|
+
block.call(orig_ds.select_append(*associated_key_array))
|
|
651
|
+
else
|
|
652
|
+
ds.select_append(*associated_key_array)
|
|
653
|
+
end
|
|
640
654
|
end
|
|
641
655
|
if self[:eager_graph]
|
|
642
656
|
raise(Error, "cannot eagerly load a #{self[:type]} association that uses :eager_graph") if eager_loading_use_associated_key?
|
|
@@ -747,8 +761,8 @@ module Sequel
|
|
|
747
761
|
|
|
748
762
|
# If +s+ is an array, map +s+ over the block. Otherwise, just call the
|
|
749
763
|
# block with +s+.
|
|
750
|
-
def transform(s)
|
|
751
|
-
s.is_a?(Array) ? s.map(&
|
|
764
|
+
def transform(s, &block)
|
|
765
|
+
s.is_a?(Array) ? s.map(&block) : (yield s)
|
|
752
766
|
end
|
|
753
767
|
|
|
754
768
|
# What eager limit strategy should be used when true is given as the value,
|
|
@@ -791,7 +805,7 @@ module Sequel
|
|
|
791
805
|
|
|
792
806
|
# Whether the placeholder loader can be used to load the association.
|
|
793
807
|
def use_placeholder_loader?
|
|
794
|
-
|
|
808
|
+
self[:use_placeholder_loader]
|
|
795
809
|
end
|
|
796
810
|
end
|
|
797
811
|
|
|
@@ -1239,7 +1253,9 @@ module Sequel
|
|
|
1239
1253
|
else
|
|
1240
1254
|
assoc_record.values.delete(left_key_alias)
|
|
1241
1255
|
end
|
|
1242
|
-
|
|
1256
|
+
|
|
1257
|
+
objects = h[hash_key]
|
|
1258
|
+
|
|
1243
1259
|
if assign_singular
|
|
1244
1260
|
objects.each do |object|
|
|
1245
1261
|
object.associations[name] ||= assoc_record
|
|
@@ -1612,9 +1628,10 @@ module Sequel
|
|
|
1612
1628
|
# is hash or array of two element arrays. Consider also specifying the :graph_block
|
|
1613
1629
|
# option if the value for this option is not a hash or array of two element arrays
|
|
1614
1630
|
# and you plan to use this association in eager_graph or association_join.
|
|
1615
|
-
# :dataset :: A proc that is
|
|
1631
|
+
# :dataset :: A proc that is used to define the method to get the base dataset to use (before the other
|
|
1616
1632
|
# options are applied). If the proc accepts an argument, it is passed the related
|
|
1617
|
-
# association reflection.
|
|
1633
|
+
# association reflection. It is a best practice to always have the dataset accept an argument
|
|
1634
|
+
# and use the argument to return the appropriate dataset.
|
|
1618
1635
|
# :distinct :: Use the DISTINCT clause when selecting associating object, both when
|
|
1619
1636
|
# lazy loading and eager loading via .eager (but not when using .eager_graph).
|
|
1620
1637
|
# :eager :: The associations to eagerly load via +eager+ when loading the associated object(s).
|
|
@@ -1785,11 +1802,12 @@ module Sequel
|
|
|
1785
1802
|
opts.merge!(:type => type, :name => name, :cache=>({} if cache_associations), :model => self)
|
|
1786
1803
|
|
|
1787
1804
|
opts[:block] = block if block
|
|
1788
|
-
|
|
1805
|
+
opts[:instance_specific] = true if orig_opts[:dataset]
|
|
1806
|
+
if !opts.has_key?(:instance_specific) && (block || orig_opts[:block])
|
|
1789
1807
|
# It's possible the association is instance specific, in that it depends on
|
|
1790
1808
|
# values other than the foreign key value. This needs to be checked for
|
|
1791
1809
|
# in certain places to disable optimizations.
|
|
1792
|
-
opts[:instance_specific] =
|
|
1810
|
+
opts[:instance_specific] = _association_instance_specific_default(name)
|
|
1793
1811
|
end
|
|
1794
1812
|
opts = assoc_class.new.merge!(opts)
|
|
1795
1813
|
|
|
@@ -1797,6 +1815,7 @@ module Sequel
|
|
|
1797
1815
|
raise(Error, "cannot clone an association to an association of different type (association #{name} with type #{type} cloning #{opts[:clone]} with type #{cloned_assoc[:type]})")
|
|
1798
1816
|
end
|
|
1799
1817
|
|
|
1818
|
+
opts[:use_placeholder_loader] = !opts[:instance_specific] && !opts[:eager_graph]
|
|
1800
1819
|
opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
|
|
1801
1820
|
opts[:graph_join_type] ||= :left_outer
|
|
1802
1821
|
opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
|
|
@@ -1893,6 +1912,12 @@ module Sequel
|
|
|
1893
1912
|
Plugins.def_dataset_methods(self, [:eager, :eager_graph, :eager_graph_with_options, :association_join, :association_full_join, :association_inner_join, :association_left_join, :association_right_join])
|
|
1894
1913
|
|
|
1895
1914
|
private
|
|
1915
|
+
|
|
1916
|
+
# The default value for the instance_specific option, if the association
|
|
1917
|
+
# could be instance specific and the :instance_specific option is not specified.
|
|
1918
|
+
def _association_instance_specific_default(_)
|
|
1919
|
+
true
|
|
1920
|
+
end
|
|
1896
1921
|
|
|
1897
1922
|
# The module to use for the association's methods. Defaults to
|
|
1898
1923
|
# the overridable_methods_module.
|
|
@@ -1904,7 +1929,7 @@ module Sequel
|
|
|
1904
1929
|
# can be easily overridden in the class itself while allowing for
|
|
1905
1930
|
# super to be called.
|
|
1906
1931
|
def association_module_def(name, opts=OPTS, &block)
|
|
1907
|
-
association_module(opts).
|
|
1932
|
+
association_module(opts).send(:define_method, name, &block)
|
|
1908
1933
|
end
|
|
1909
1934
|
|
|
1910
1935
|
# Add a private method to the module included in the class.
|
|
@@ -1939,6 +1964,11 @@ module Sequel
|
|
|
1939
1964
|
end
|
|
1940
1965
|
|
|
1941
1966
|
association_module_def(opts.dataset_method, opts){_dataset(opts)}
|
|
1967
|
+
if opts[:block]
|
|
1968
|
+
opts[:block_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_block", 1, &opts[:block])
|
|
1969
|
+
end
|
|
1970
|
+
opts[:dataset_opt_arity] = opts[:dataset].arity == 0 ? 0 : 1
|
|
1971
|
+
opts[:dataset_opt_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_dataset_opt", opts[:dataset_opt_arity], &opts[:dataset])
|
|
1942
1972
|
def_association_method(opts)
|
|
1943
1973
|
|
|
1944
1974
|
return if opts[:read_only]
|
|
@@ -2109,9 +2139,7 @@ module Sequel
|
|
|
2109
2139
|
|
|
2110
2140
|
eager_load_results(opts, eo) do |assoc_record|
|
|
2111
2141
|
hash_key = uses_cks ? pk_meths.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(opts.primary_key_method)
|
|
2112
|
-
|
|
2113
|
-
objects.each{|object| object.associations[name] = assoc_record}
|
|
2114
|
-
end
|
|
2142
|
+
h[hash_key].each{|object| object.associations[name] = assoc_record}
|
|
2115
2143
|
end
|
|
2116
2144
|
end
|
|
2117
2145
|
|
|
@@ -2124,7 +2152,7 @@ module Sequel
|
|
|
2124
2152
|
graph_cks = opts[:graph_keys]
|
|
2125
2153
|
opts[:eager_grapher] ||= proc do |eo|
|
|
2126
2154
|
ds = eo[:self]
|
|
2127
|
-
ds.graph(eager_graph_dataset(opts, eo), use_only_conditions ? only_conditions : opts.primary_keys.zip(graph_cks) + conditions,
|
|
2155
|
+
ds.graph(eager_graph_dataset(opts, eo), use_only_conditions ? only_conditions : opts.primary_keys.zip(graph_cks) + conditions, eo.merge(:select=>select, :join_type=>eo[:join_type]||join_type, :qualify=>:deep), &graph_block)
|
|
2128
2156
|
end
|
|
2129
2157
|
|
|
2130
2158
|
return if opts[:read_only]
|
|
@@ -2158,7 +2186,7 @@ module Sequel
|
|
|
2158
2186
|
eager_load_results(opts, eo) do |assoc_record|
|
|
2159
2187
|
assoc_record.values.delete(delete_rn) if delete_rn
|
|
2160
2188
|
hash_key = uses_cks ? km.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(km)
|
|
2161
|
-
|
|
2189
|
+
objects = h[hash_key]
|
|
2162
2190
|
if assign_singular
|
|
2163
2191
|
objects.each do |object|
|
|
2164
2192
|
unless object.associations[name]
|
|
@@ -2184,7 +2212,7 @@ module Sequel
|
|
|
2184
2212
|
graph_block = opts[:graph_block]
|
|
2185
2213
|
opts[:eager_grapher] ||= proc do |eo|
|
|
2186
2214
|
ds = eo[:self]
|
|
2187
|
-
ds = ds.graph(opts.apply_eager_graph_limit_strategy(eo[:limit_strategy], eager_graph_dataset(opts, eo)), use_only_conditions ? only_conditions : cks.zip(pkcs) + conditions,
|
|
2215
|
+
ds = ds.graph(opts.apply_eager_graph_limit_strategy(eo[:limit_strategy], eager_graph_dataset(opts, eo)), use_only_conditions ? only_conditions : cks.zip(pkcs) + conditions, eo.merge(:select=>select, :join_type=>eo[:join_type]||join_type, :qualify=>:deep), &graph_block)
|
|
2188
2216
|
# We only load reciprocals for one_to_many associations, as other reciprocals don't make sense
|
|
2189
2217
|
ds.opts[:eager_graph][:reciprocals][eo[:table_alias]] = opts.reciprocal
|
|
2190
2218
|
ds
|
|
@@ -2199,12 +2227,28 @@ module Sequel
|
|
|
2199
2227
|
if one_to_one
|
|
2200
2228
|
opts[:setter] ||= proc do |o|
|
|
2201
2229
|
up_ds = _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| get_column_value(k)})))
|
|
2230
|
+
|
|
2231
|
+
if (froms = up_ds.opts[:from]) && (from = froms[0]) && (from.is_a?(Sequel::Dataset) || (from.is_a?(Sequel::SQL::AliasedExpression) && from.expression.is_a?(Sequel::Dataset)))
|
|
2232
|
+
if old = up_ds.first
|
|
2233
|
+
cks.each{|k| old.set_column_value(:"#{k}=", nil)}
|
|
2234
|
+
end
|
|
2235
|
+
save_old = true
|
|
2236
|
+
end
|
|
2237
|
+
|
|
2202
2238
|
if o
|
|
2203
|
-
|
|
2239
|
+
if !o.new? && !save_old
|
|
2240
|
+
up_ds = up_ds.exclude(o.pk_hash)
|
|
2241
|
+
end
|
|
2204
2242
|
cks.zip(cpks).each{|k, pk| o.set_column_value(:"#{k}=", get_column_value(pk))}
|
|
2205
2243
|
end
|
|
2244
|
+
|
|
2206
2245
|
checked_transaction do
|
|
2207
|
-
|
|
2246
|
+
if save_old
|
|
2247
|
+
old.save(save_opts) || raise(Sequel::Error, "invalid previously associated object, cannot save") if old
|
|
2248
|
+
else
|
|
2249
|
+
up_ds.skip_limit_check.update(ck_nil_hash)
|
|
2250
|
+
end
|
|
2251
|
+
|
|
2208
2252
|
o.save(save_opts) || raise(Sequel::Error, "invalid associated object, cannot save") if o
|
|
2209
2253
|
end
|
|
2210
2254
|
end
|
|
@@ -2282,7 +2326,8 @@ module Sequel
|
|
|
2282
2326
|
end
|
|
2283
2327
|
ds = ds.clone(:model_object => self)
|
|
2284
2328
|
ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph] && opts.eager_graph_lazy_dataset?
|
|
2285
|
-
|
|
2329
|
+
# block method is private
|
|
2330
|
+
ds = send(opts[:block_method], ds) if opts[:block_method]
|
|
2286
2331
|
ds
|
|
2287
2332
|
end
|
|
2288
2333
|
|
|
@@ -2305,10 +2350,11 @@ module Sequel
|
|
|
2305
2350
|
# Return an association dataset for the given association reflection
|
|
2306
2351
|
def _dataset(opts)
|
|
2307
2352
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
|
2308
|
-
ds = if opts[:
|
|
2309
|
-
|
|
2353
|
+
ds = if opts[:dataset_opt_arity] == 1
|
|
2354
|
+
# dataset_opt_method is private
|
|
2355
|
+
send(opts[:dataset_opt_method], opts)
|
|
2310
2356
|
else
|
|
2311
|
-
|
|
2357
|
+
send(opts[:dataset_opt_method])
|
|
2312
2358
|
end
|
|
2313
2359
|
_apply_association_options(opts, ds)
|
|
2314
2360
|
end
|
|
@@ -2401,7 +2447,32 @@ module Sequel
|
|
|
2401
2447
|
# cached associations.
|
|
2402
2448
|
def change_column_value(column, value)
|
|
2403
2449
|
if assocs = model.autoreloading_associations[column]
|
|
2404
|
-
|
|
2450
|
+
vals = @values
|
|
2451
|
+
if new?
|
|
2452
|
+
# Do deeper checking for new objects, so that associations are
|
|
2453
|
+
# not deleted when values do not change. This code is run at
|
|
2454
|
+
# a higher level for existing objects.
|
|
2455
|
+
if value == (c = vals[column]) && value.class == c.class
|
|
2456
|
+
# If the value is the same, there is no reason to delete
|
|
2457
|
+
# the related associations, so exit early in that case.
|
|
2458
|
+
return super
|
|
2459
|
+
end
|
|
2460
|
+
|
|
2461
|
+
only_delete_nil = c.nil?
|
|
2462
|
+
elsif vals[column].nil?
|
|
2463
|
+
only_delete_nil = true
|
|
2464
|
+
end
|
|
2465
|
+
|
|
2466
|
+
if only_delete_nil
|
|
2467
|
+
# If the current foreign key value is nil, but the association
|
|
2468
|
+
# is already present in the cache, it was probably added to the
|
|
2469
|
+
# cache for a reason, and we do not want to delete it in that case.
|
|
2470
|
+
# However, we still want to delete associations with nil values
|
|
2471
|
+
# to remove the cached false negative.
|
|
2472
|
+
assocs.each{|a| associations.delete(a) if associations[a].nil?}
|
|
2473
|
+
else
|
|
2474
|
+
assocs.each{|a| associations.delete(a)}
|
|
2475
|
+
end
|
|
2405
2476
|
end
|
|
2406
2477
|
super
|
|
2407
2478
|
end
|
|
@@ -2567,13 +2638,25 @@ module Sequel
|
|
|
2567
2638
|
# Set the given object as the associated object for the given *_to_one association reflection
|
|
2568
2639
|
def _set_associated_object(opts, o)
|
|
2569
2640
|
a = associations[opts[:name]]
|
|
2570
|
-
|
|
2641
|
+
reciprocal = opts.reciprocal
|
|
2642
|
+
if set_associated_object_if_same?
|
|
2643
|
+
if reciprocal
|
|
2644
|
+
remove_reciprocal = a && (a != o || a.associations[reciprocal] != self)
|
|
2645
|
+
add_reciprocal = o && o.associations[reciprocal] != self
|
|
2646
|
+
end
|
|
2647
|
+
else
|
|
2648
|
+
return if a && a == o
|
|
2649
|
+
if reciprocal
|
|
2650
|
+
remove_reciprocal = a
|
|
2651
|
+
add_reciprocal = o
|
|
2652
|
+
end
|
|
2653
|
+
end
|
|
2571
2654
|
run_association_callbacks(opts, :before_set, o)
|
|
2572
|
-
remove_reciprocal_object(opts, a) if
|
|
2655
|
+
remove_reciprocal_object(opts, a) if remove_reciprocal
|
|
2573
2656
|
# Allow calling private _setter method
|
|
2574
2657
|
send(opts[:_setter_method], o)
|
|
2575
2658
|
associations[opts[:name]] = o
|
|
2576
|
-
add_reciprocal_object(opts, o) if
|
|
2659
|
+
add_reciprocal_object(opts, o) if add_reciprocal
|
|
2577
2660
|
run_association_callbacks(opts, :after_set, o)
|
|
2578
2661
|
o
|
|
2579
2662
|
end
|
|
@@ -2628,7 +2711,7 @@ module Sequel
|
|
|
2628
2711
|
# Album.eager(:artist, :genre).all
|
|
2629
2712
|
# Album.eager_graph(:artist, :genre).all
|
|
2630
2713
|
# Album.eager(:artist).eager(:genre).all
|
|
2631
|
-
# Album.eager_graph(:artist).
|
|
2714
|
+
# Album.eager_graph(:artist).eager_graph(:genre).all
|
|
2632
2715
|
# Artist.eager(albums: :tracks).all
|
|
2633
2716
|
# Artist.eager_graph(albums: :tracks).all
|
|
2634
2717
|
# Artist.eager(albums: {tracks: :genre}).all
|
|
@@ -2661,13 +2744,79 @@ module Sequel
|
|
|
2661
2744
|
end
|
|
2662
2745
|
|
|
2663
2746
|
# Adds one or more INNER JOINs to the existing dataset using the keys and conditions
|
|
2664
|
-
# specified by the given association.
|
|
2665
|
-
#
|
|
2747
|
+
# specified by the given association(s). Take the same arguments as eager_graph, and
|
|
2748
|
+
# operates similarly, but only adds the joins as opposed to making the other changes
|
|
2749
|
+
# (such as adding selected columns and setting up eager loading).
|
|
2750
|
+
#
|
|
2751
|
+
# The following methods also exist for specifying a different type of JOIN:
|
|
2666
2752
|
#
|
|
2667
2753
|
# association_full_join :: FULL JOIN
|
|
2668
2754
|
# association_inner_join :: INNER JOIN
|
|
2669
2755
|
# association_left_join :: LEFT JOIN
|
|
2670
2756
|
# association_right_join :: RIGHT JOIN
|
|
2757
|
+
#
|
|
2758
|
+
# Examples:
|
|
2759
|
+
#
|
|
2760
|
+
# # For each album, association_join load the artist
|
|
2761
|
+
# Album.association_join(:artist).all
|
|
2762
|
+
# # SELECT *
|
|
2763
|
+
# # FROM albums
|
|
2764
|
+
# # INNER JOIN artists AS artist ON (artists.id = albums.artist_id)
|
|
2765
|
+
#
|
|
2766
|
+
# # For each album, association_join load the artist, using a specified alias
|
|
2767
|
+
# Album.association_join(Sequel[:artist].as(:a)).all
|
|
2768
|
+
# # SELECT *
|
|
2769
|
+
# # FROM albums
|
|
2770
|
+
# # INNER JOIN artists AS a ON (a.id = albums.artist_id)
|
|
2771
|
+
#
|
|
2772
|
+
# # For each album, association_join load the artist and genre
|
|
2773
|
+
# Album.association_join(:artist, :genre).all
|
|
2774
|
+
# Album.association_join(:artist).association_join(:genre).all
|
|
2775
|
+
# # SELECT *
|
|
2776
|
+
# # FROM albums
|
|
2777
|
+
# # INNER JOIN artists AS artist ON (artist.id = albums.artist_id)
|
|
2778
|
+
# # INNER JOIN genres AS genre ON (genre.id = albums.genre_id)
|
|
2779
|
+
#
|
|
2780
|
+
# # For each artist, association_join load albums and tracks for each album
|
|
2781
|
+
# Artist.association_join(albums: :tracks).all
|
|
2782
|
+
# # SELECT *
|
|
2783
|
+
# # FROM artists
|
|
2784
|
+
# # INNER JOIN albums ON (albums.artist_id = artists.id)
|
|
2785
|
+
# # INNER JOIN tracks ON (tracks.album_id = albums.id)
|
|
2786
|
+
#
|
|
2787
|
+
# # For each artist, association_join load albums, tracks for each album, and genre for each track
|
|
2788
|
+
# Artist.association_join(albums: {tracks: :genre}).all
|
|
2789
|
+
# # SELECT *
|
|
2790
|
+
# # FROM artists
|
|
2791
|
+
# # INNER JOIN albums ON (albums.artist_id = artists.id)
|
|
2792
|
+
# # INNER JOIN tracks ON (tracks.album_id = albums.id)
|
|
2793
|
+
# # INNER JOIN genres AS genre ON (genre.id = tracks.genre_id)
|
|
2794
|
+
#
|
|
2795
|
+
# # For each artist, association_join load albums with year > 1990
|
|
2796
|
+
# Artist.association_join(albums: proc{|ds| ds.where{year > 1990}}).all
|
|
2797
|
+
# # SELECT *
|
|
2798
|
+
# # FROM artists
|
|
2799
|
+
# # INNER JOIN (
|
|
2800
|
+
# # SELECT * FROM albums WHERE (year > 1990)
|
|
2801
|
+
# # ) AS albums ON (albums.artist_id = artists.id)
|
|
2802
|
+
#
|
|
2803
|
+
# # For each artist, association_join load albums and tracks 1-10 for each album
|
|
2804
|
+
# Artist.association_join(albums: {tracks: proc{|ds| ds.where(number: 1..10)}}).all
|
|
2805
|
+
# # SELECT *
|
|
2806
|
+
# # FROM artists
|
|
2807
|
+
# # INNER JOIN albums ON (albums.artist_id = artists.id)
|
|
2808
|
+
# # INNER JOIN (
|
|
2809
|
+
# # SELECT * FROM tracks WHERE ((number >= 1) AND (number <= 10))
|
|
2810
|
+
# # ) AS tracks ON (tracks.albums_id = albums.id)
|
|
2811
|
+
#
|
|
2812
|
+
# # For each artist, association_join load albums with year > 1990, and tracks for those albums
|
|
2813
|
+
# Artist.association_join(albums: {proc{|ds| ds.where{year > 1990}}=>:tracks}).all
|
|
2814
|
+
# # SELECT *
|
|
2815
|
+
# # FROM artists
|
|
2816
|
+
# # INNER JOIN (
|
|
2817
|
+
# # SELECT * FROM albums WHERE (year > 1990)
|
|
2818
|
+
# # ) AS albums ON (albums.artist_id = artists.id)
|
|
2819
|
+
# # INNER JOIN tracks ON (tracks.album_id = albums.id)
|
|
2671
2820
|
def association_join(*associations)
|
|
2672
2821
|
association_inner_join(*associations)
|
|
2673
2822
|
end
|
|
@@ -2681,8 +2830,8 @@ module Sequel
|
|
|
2681
2830
|
# creates a subquery to the join table.
|
|
2682
2831
|
def complex_expression_sql_append(sql, op, args)
|
|
2683
2832
|
r = args[1]
|
|
2684
|
-
if (((op == :'=' || op == :'!=')
|
|
2685
|
-
(multiple = ((op == :IN || op == :'NOT IN')
|
|
2833
|
+
if (((op == :'=' || op == :'!=') && r.is_a?(Sequel::Model)) ||
|
|
2834
|
+
(multiple = ((op == :IN || op == :'NOT IN') && ((is_ds = r.is_a?(Sequel::Dataset)) || (r.respond_to?(:all?) && r.all?{|x| x.is_a?(Sequel::Model)})))))
|
|
2686
2835
|
l = args[0]
|
|
2687
2836
|
if ar = model.association_reflections[l]
|
|
2688
2837
|
if multiple
|
|
@@ -2747,11 +2896,61 @@ module Sequel
|
|
|
2747
2896
|
#
|
|
2748
2897
|
# Each association's order, if defined, is respected.
|
|
2749
2898
|
# If the association uses a block or has an :eager_block argument, it is used.
|
|
2899
|
+
#
|
|
2900
|
+
# To modify the associated dataset that will be used for the eager load, you should use a
|
|
2901
|
+
# hash for the association, with the key being the association name symbol, and the value being
|
|
2902
|
+
# a callable object that is called with the associated dataset and should return a modified
|
|
2903
|
+
# dataset. If that association also has dependent associations, instead of a callable object,
|
|
2904
|
+
# use a hash with the callable object being the key, and the dependent association(s) as the value.
|
|
2905
|
+
#
|
|
2906
|
+
# Examples:
|
|
2907
|
+
#
|
|
2908
|
+
# # For each album, eager load the artist
|
|
2909
|
+
# Album.eager(:artist).all
|
|
2910
|
+
# # SELECT * FROM albums
|
|
2911
|
+
# # SELECT * FROM artists WHERE (id IN (...))
|
|
2912
|
+
#
|
|
2913
|
+
# # For each album, eager load the artist and genre
|
|
2914
|
+
# Album.eager(:artist, :genre).all
|
|
2915
|
+
# Album.eager(:artist).eager(:genre).all
|
|
2916
|
+
# # SELECT * FROM albums
|
|
2917
|
+
# # SELECT * FROM artists WHERE (id IN (...))
|
|
2918
|
+
# # SELECT * FROM genres WHERE (id IN (...))
|
|
2919
|
+
#
|
|
2920
|
+
# # For each artist, eager load albums and tracks for each album
|
|
2921
|
+
# Artist.eager(albums: :tracks).all
|
|
2922
|
+
# # SELECT * FROM artists
|
|
2923
|
+
# # SELECT * FROM albums WHERE (artist_id IN (...))
|
|
2924
|
+
# # SELECT * FROM tracks WHERE (album_id IN (...))
|
|
2925
|
+
#
|
|
2926
|
+
# # For each artist, eager load albums, tracks for each album, and genre for each track
|
|
2927
|
+
# Artist.eager(albums: {tracks: :genre}).all
|
|
2928
|
+
# # SELECT * FROM artists
|
|
2929
|
+
# # SELECT * FROM albums WHERE (artist_id IN (...))
|
|
2930
|
+
# # SELECT * FROM tracks WHERE (album_id IN (...))
|
|
2931
|
+
# # SELECT * FROM genre WHERE (id IN (...))
|
|
2932
|
+
#
|
|
2933
|
+
# # For each artist, eager load albums with year > 1990
|
|
2934
|
+
# Artist.eager(albums: proc{|ds| ds.where{year > 1990}}).all
|
|
2935
|
+
# # SELECT * FROM artists
|
|
2936
|
+
# # SELECT * FROM albums WHERE ((year > 1990) AND (artist_id IN (...)))
|
|
2937
|
+
#
|
|
2938
|
+
# # For each artist, eager load albums and tracks 1-10 for each album
|
|
2939
|
+
# Artist.eager(albums: {tracks: proc{|ds| ds.where(number: 1..10)}}).all
|
|
2940
|
+
# # SELECT * FROM artists
|
|
2941
|
+
# # SELECT * FROM albums WHERE (artist_id IN (...))
|
|
2942
|
+
# # SELECT * FROM tracks WHERE ((number >= 1) AND (number <= 10) AND (album_id IN (...)))
|
|
2943
|
+
#
|
|
2944
|
+
# # For each artist, eager load albums with year > 1990, and tracks for those albums
|
|
2945
|
+
# Artist.eager(albums: {proc{|ds| ds.where{year > 1990}}=>:tracks}).all
|
|
2946
|
+
# # SELECT * FROM artists
|
|
2947
|
+
# # SELECT * FROM albums WHERE ((year > 1990) AND (artist_id IN (...)))
|
|
2948
|
+
# # SELECT * FROM albums WHERE (artist_id IN (...))
|
|
2750
2949
|
def eager(*associations)
|
|
2751
2950
|
opts = @opts[:eager]
|
|
2752
2951
|
association_opts = eager_options_for_associations(associations)
|
|
2753
|
-
opts = opts ?
|
|
2754
|
-
clone(:eager=>opts)
|
|
2952
|
+
opts = opts ? opts.merge(association_opts) : association_opts
|
|
2953
|
+
clone(:eager=>opts.freeze)
|
|
2755
2954
|
end
|
|
2756
2955
|
|
|
2757
2956
|
# The secondary eager loading method. Loads all associations in a single query. This
|
|
@@ -2775,6 +2974,86 @@ module Sequel
|
|
|
2775
2974
|
#
|
|
2776
2975
|
# Like +eager+, you need to call +all+ on the dataset for the eager loading to work. If you just
|
|
2777
2976
|
# call +each+, it will yield plain hashes, each containing all columns from all the tables.
|
|
2977
|
+
#
|
|
2978
|
+
# To modify the associated dataset that will be joined to the current dataset, you should use a
|
|
2979
|
+
# hash for the association, with the key being the association name symbol, and the value being
|
|
2980
|
+
# a callable object that is called with the associated dataset and should return a modified
|
|
2981
|
+
# dataset. If that association also has dependent associations, instead of a callable object,
|
|
2982
|
+
# use a hash with the callable object being the key, and the dependent association(s) as the value.
|
|
2983
|
+
#
|
|
2984
|
+
# You can specify an custom alias and/or join type on a per-association basis by providing an
|
|
2985
|
+
# Sequel::SQL::AliasedExpression object instead of an a Symbol for the association name.
|
|
2986
|
+
#
|
|
2987
|
+
# Examples:
|
|
2988
|
+
#
|
|
2989
|
+
# # For each album, eager_graph load the artist
|
|
2990
|
+
# Album.eager_graph(:artist).all
|
|
2991
|
+
# # SELECT ...
|
|
2992
|
+
# # FROM albums
|
|
2993
|
+
# # LEFT OUTER JOIN artists AS artist ON (artists.id = albums.artist_id)
|
|
2994
|
+
#
|
|
2995
|
+
# # For each album, eager_graph load the artist, using a specified alias
|
|
2996
|
+
# Album.eager_graph(Sequel[:artist].as(:a)).all
|
|
2997
|
+
# # SELECT ...
|
|
2998
|
+
# # FROM albums
|
|
2999
|
+
# # LEFT OUTER JOIN artists AS a ON (a.id = albums.artist_id)
|
|
3000
|
+
#
|
|
3001
|
+
# # For each album, eager_graph load the artist, using a specified alias
|
|
3002
|
+
# # and custom join type
|
|
3003
|
+
#
|
|
3004
|
+
# Album.eager_graph(Sequel[:artist].as(:a, join_type: :inner)).all
|
|
3005
|
+
# # SELECT ...
|
|
3006
|
+
# # FROM albums
|
|
3007
|
+
# # INNER JOIN artists AS a ON (a.id = albums.artist_id)
|
|
3008
|
+
#
|
|
3009
|
+
# # For each album, eager_graph load the artist and genre
|
|
3010
|
+
# Album.eager_graph(:artist, :genre).all
|
|
3011
|
+
# Album.eager_graph(:artist).eager_graph(:genre).all
|
|
3012
|
+
# # SELECT ...
|
|
3013
|
+
# # FROM albums
|
|
3014
|
+
# # LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id)
|
|
3015
|
+
# # LEFT OUTER JOIN genres AS genre ON (genre.id = albums.genre_id)
|
|
3016
|
+
#
|
|
3017
|
+
# # For each artist, eager_graph load albums and tracks for each album
|
|
3018
|
+
# Artist.eager_graph(albums: :tracks).all
|
|
3019
|
+
# # SELECT ...
|
|
3020
|
+
# # FROM artists
|
|
3021
|
+
# # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
|
3022
|
+
# # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
|
|
3023
|
+
#
|
|
3024
|
+
# # For each artist, eager_graph load albums, tracks for each album, and genre for each track
|
|
3025
|
+
# Artist.eager_graph(albums: {tracks: :genre}).all
|
|
3026
|
+
# # SELECT ...
|
|
3027
|
+
# # FROM artists
|
|
3028
|
+
# # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
|
3029
|
+
# # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
|
|
3030
|
+
# # LEFT OUTER JOIN genres AS genre ON (genre.id = tracks.genre_id)
|
|
3031
|
+
#
|
|
3032
|
+
# # For each artist, eager_graph load albums with year > 1990
|
|
3033
|
+
# Artist.eager_graph(albums: proc{|ds| ds.where{year > 1990}}).all
|
|
3034
|
+
# # SELECT ...
|
|
3035
|
+
# # FROM artists
|
|
3036
|
+
# # LEFT OUTER JOIN (
|
|
3037
|
+
# # SELECT * FROM albums WHERE (year > 1990)
|
|
3038
|
+
# # ) AS albums ON (albums.artist_id = artists.id)
|
|
3039
|
+
#
|
|
3040
|
+
# # For each artist, eager_graph load albums and tracks 1-10 for each album
|
|
3041
|
+
# Artist.eager_graph(albums: {tracks: proc{|ds| ds.where(number: 1..10)}}).all
|
|
3042
|
+
# # SELECT ...
|
|
3043
|
+
# # FROM artists
|
|
3044
|
+
# # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
|
3045
|
+
# # LEFT OUTER JOIN (
|
|
3046
|
+
# # SELECT * FROM tracks WHERE ((number >= 1) AND (number <= 10))
|
|
3047
|
+
# # ) AS tracks ON (tracks.albums_id = albums.id)
|
|
3048
|
+
#
|
|
3049
|
+
# # For each artist, eager_graph load albums with year > 1990, and tracks for those albums
|
|
3050
|
+
# Artist.eager_graph(albums: {proc{|ds| ds.where{year > 1990}}=>:tracks}).all
|
|
3051
|
+
# # SELECT ...
|
|
3052
|
+
# # FROM artists
|
|
3053
|
+
# # LEFT OUTER JOIN (
|
|
3054
|
+
# # SELECT * FROM albums WHERE (year > 1990)
|
|
3055
|
+
# # ) AS albums ON (albums.artist_id = artists.id)
|
|
3056
|
+
# # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
|
|
2778
3057
|
def eager_graph(*associations)
|
|
2779
3058
|
eager_graph_with_options(associations)
|
|
2780
3059
|
end
|
|
@@ -2800,8 +3079,11 @@ module Sequel
|
|
|
2800
3079
|
# significantly slower in some cases (perhaps even the majority of cases), so you should
|
|
2801
3080
|
# only use this if you have benchmarked that it is faster for your use cases.
|
|
2802
3081
|
def eager_graph_with_options(associations, opts=OPTS)
|
|
3082
|
+
return self if associations.empty?
|
|
3083
|
+
|
|
3084
|
+
opts = opts.dup unless opts.frozen?
|
|
2803
3085
|
associations = [associations] unless associations.is_a?(Array)
|
|
2804
|
-
if eg = @opts[:eager_graph]
|
|
3086
|
+
ds = if eg = @opts[:eager_graph]
|
|
2805
3087
|
eg = eg.dup
|
|
2806
3088
|
[:requirements, :reflections, :reciprocals, :limits].each{|k| eg[k] = eg[k].dup}
|
|
2807
3089
|
eg[:local] = opts
|
|
@@ -2815,8 +3097,12 @@ module Sequel
|
|
|
2815
3097
|
# :limits :: Any limit/offset array slicing that need to be handled in ruby land after loading
|
|
2816
3098
|
opts = {:requirements=>{}, :master=>alias_symbol(first_source), :reflections=>{}, :reciprocals=>{}, :limits=>{}, :local=>opts, :cartesian_product_number=>0, :row_proc=>row_proc}
|
|
2817
3099
|
ds = clone(:eager_graph=>opts)
|
|
2818
|
-
ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations).naked
|
|
3100
|
+
ds = ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations).naked
|
|
2819
3101
|
end
|
|
3102
|
+
|
|
3103
|
+
ds.opts[:eager_graph].freeze
|
|
3104
|
+
ds.opts[:eager_graph].each_value{|v| v.freeze if v.is_a?(Hash)}
|
|
3105
|
+
ds
|
|
2820
3106
|
end
|
|
2821
3107
|
|
|
2822
3108
|
# If the dataset is being eagerly loaded, default to calling all
|
|
@@ -2864,11 +3150,16 @@ module Sequel
|
|
|
2864
3150
|
# ta :: table_alias used for the parent association
|
|
2865
3151
|
# requirements :: an array, used as a stack for requirements
|
|
2866
3152
|
# r :: association reflection for the current association, or an SQL::AliasedExpression
|
|
2867
|
-
# with the reflection as the expression
|
|
3153
|
+
# with the reflection as the expression, the alias base as the alias (or nil to
|
|
3154
|
+
# use the default alias), and an optional hash with a :join_type entry as the columns
|
|
3155
|
+
# to use a custom join type.
|
|
2868
3156
|
# *associations :: any associations dependent on this one
|
|
2869
3157
|
def eager_graph_association(ds, model, ta, requirements, r, *associations)
|
|
2870
3158
|
if r.is_a?(SQL::AliasedExpression)
|
|
2871
3159
|
alias_base = r.alias
|
|
3160
|
+
if r.columns.is_a?(Hash)
|
|
3161
|
+
join_type = r.columns[:join_type]
|
|
3162
|
+
end
|
|
2872
3163
|
r = r.expression
|
|
2873
3164
|
else
|
|
2874
3165
|
alias_base = r[:graph_alias_base]
|
|
@@ -2891,7 +3182,7 @@ module Sequel
|
|
|
2891
3182
|
raise Error, "Cannot eager_graph association when :conditions specified and not a hash or an array of pairs. Specify :graph_conditions, :graph_only_conditions, or :graph_block for the association. Model: #{r[:model]}, association: #{r[:name]}"
|
|
2892
3183
|
end
|
|
2893
3184
|
|
|
2894
|
-
ds = loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>(ta == ds.opts[:eager_graph][:master]) ? first_source : qualifier_from_alias_symbol(ta, first_source), :callback=>callback, :join_type=>local_opts[:join_type], :join_only=>local_opts[:join_only], :limit_strategy=>limit_strategy, :from_self_alias=>ds.opts[:eager_graph][:master])
|
|
3185
|
+
ds = loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>(ta == ds.opts[:eager_graph][:master]) ? first_source : qualifier_from_alias_symbol(ta, first_source), :callback=>callback, :join_type=>join_type || local_opts[:join_type], :join_only=>local_opts[:join_only], :limit_strategy=>limit_strategy, :from_self_alias=>ds.opts[:eager_graph][:master])
|
|
2895
3186
|
if r[:order_eager_graph] && (order = r.fetch(:graph_order, r[:order]))
|
|
2896
3187
|
ds = ds.order_append(*qualified_expression(order, assoc_table_alias))
|
|
2897
3188
|
end
|
|
@@ -2916,7 +3207,6 @@ module Sequel
|
|
|
2916
3207
|
# requirements :: an array, used as a stack for requirements
|
|
2917
3208
|
# *associations :: the associations to add to the graph
|
|
2918
3209
|
def eager_graph_associations(ds, model, ta, requirements, *associations)
|
|
2919
|
-
return ds if associations.empty?
|
|
2920
3210
|
associations.flatten.each do |association|
|
|
2921
3211
|
ds = case association
|
|
2922
3212
|
when Symbol, SQL::AliasedExpression
|
|
@@ -2936,7 +3226,7 @@ module Sequel
|
|
|
2936
3226
|
# Replace the array of plain hashes with an array of model objects will all eager_graphed
|
|
2937
3227
|
# associations set in the associations cache for each object.
|
|
2938
3228
|
def eager_graph_build_associations(hashes)
|
|
2939
|
-
hashes.replace(
|
|
3229
|
+
hashes.replace(_eager_graph_build_associations(hashes, eager_graph_loader))
|
|
2940
3230
|
end
|
|
2941
3231
|
|
|
2942
3232
|
private
|
|
@@ -2947,6 +3237,12 @@ module Sequel
|
|
|
2947
3237
|
clone(:join=>clone(:graph_from_self=>false).eager_graph_with_options(associations, :join_type=>type, :join_only=>true).opts[:join])
|
|
2948
3238
|
end
|
|
2949
3239
|
|
|
3240
|
+
# Process the array of hashes using the eager graph loader to return an array
|
|
3241
|
+
# of model objects with the associations set.
|
|
3242
|
+
def _eager_graph_build_associations(hashes, egl)
|
|
3243
|
+
egl.load(hashes)
|
|
3244
|
+
end
|
|
3245
|
+
|
|
2950
3246
|
# If the association has conditions itself, then it requires additional filters be
|
|
2951
3247
|
# added to the current dataset to ensure that the passed in object would also be
|
|
2952
3248
|
# included by the association's conditions.
|
|
@@ -3032,12 +3328,28 @@ module Sequel
|
|
|
3032
3328
|
# per-call determining of the alias base.
|
|
3033
3329
|
def eager_graph_check_association(model, association)
|
|
3034
3330
|
if association.is_a?(SQL::AliasedExpression)
|
|
3035
|
-
|
|
3331
|
+
expr = association.expression
|
|
3332
|
+
if expr.is_a?(SQL::Identifier)
|
|
3333
|
+
expr = expr.value
|
|
3334
|
+
if expr.is_a?(String)
|
|
3335
|
+
expr = expr.to_sym
|
|
3336
|
+
end
|
|
3337
|
+
end
|
|
3338
|
+
|
|
3339
|
+
SQL::AliasedExpression.new(check_association(model, expr), association.alias || expr, association.columns)
|
|
3036
3340
|
else
|
|
3037
3341
|
check_association(model, association)
|
|
3038
3342
|
end
|
|
3039
3343
|
end
|
|
3040
3344
|
|
|
3345
|
+
# The EagerGraphLoader instance used for converting eager_graph results.
|
|
3346
|
+
def eager_graph_loader
|
|
3347
|
+
unless egl = cache_get(:_model_eager_graph_loader)
|
|
3348
|
+
egl = cache_set(:_model_eager_graph_loader, EagerGraphLoader.new(self))
|
|
3349
|
+
end
|
|
3350
|
+
egl.dup
|
|
3351
|
+
end
|
|
3352
|
+
|
|
3041
3353
|
# Eagerly load all specified associations
|
|
3042
3354
|
def eager_load(a, eager_assoc=@opts[:eager])
|
|
3043
3355
|
return if a.empty?
|
|
@@ -3081,7 +3393,7 @@ module Sequel
|
|
|
3081
3393
|
associations = eager_assoc[r[:name]]
|
|
3082
3394
|
if associations.respond_to?(:call)
|
|
3083
3395
|
eager_block = associations
|
|
3084
|
-
associations =
|
|
3396
|
+
associations = OPTS
|
|
3085
3397
|
elsif associations.is_a?(Hash) && associations.length == 1 && (pr_assoc = associations.to_a.first) && pr_assoc.first.respond_to?(:call)
|
|
3086
3398
|
eager_block, associations = pr_assoc
|
|
3087
3399
|
end
|
|
@@ -3175,7 +3487,6 @@ module Sequel
|
|
|
3175
3487
|
# Hash with table alias symbol keys and [limit, offset] values
|
|
3176
3488
|
attr_reader :limit_map
|
|
3177
3489
|
|
|
3178
|
-
# Hash with table alias symbol keys and callable values used to create model instances
|
|
3179
3490
|
# The table alias symbol for the primary model
|
|
3180
3491
|
attr_reader :master
|
|
3181
3492
|
|
|
@@ -3225,12 +3536,15 @@ module Sequel
|
|
|
3225
3536
|
:offset
|
|
3226
3537
|
end
|
|
3227
3538
|
end
|
|
3539
|
+
after_load_map.freeze
|
|
3540
|
+
alias_map.freeze
|
|
3541
|
+
type_map.freeze
|
|
3228
3542
|
|
|
3229
3543
|
# Make dependency map hash out of requirements array for each association.
|
|
3230
3544
|
# This builds a tree of dependencies that will be used for recursion
|
|
3231
3545
|
# to ensure that all parts of the object graph are loaded into the
|
|
3232
3546
|
# appropriate subordinate association.
|
|
3233
|
-
@dependency_map = {}
|
|
3547
|
+
dependency_map = @dependency_map = {}
|
|
3234
3548
|
# Sort the associations by requirements length, so that
|
|
3235
3549
|
# requirements are added to the dependency hash before their
|
|
3236
3550
|
# dependencies.
|
|
@@ -3246,18 +3560,12 @@ module Sequel
|
|
|
3246
3560
|
hash[ta] = {}
|
|
3247
3561
|
end
|
|
3248
3562
|
end
|
|
3563
|
+
freezer = lambda do |h|
|
|
3564
|
+
h.freeze
|
|
3565
|
+
h.each_value(&freezer)
|
|
3566
|
+
end
|
|
3567
|
+
freezer.call(dependency_map)
|
|
3249
3568
|
|
|
3250
|
-
# This mapping is used to make sure that duplicate entries in the
|
|
3251
|
-
# result set are mapped to a single record. For example, using a
|
|
3252
|
-
# single one_to_many association with 10 associated records,
|
|
3253
|
-
# the main object column values appear in the object graph 10 times.
|
|
3254
|
-
# We map by primary key, if available, or by the object's entire values,
|
|
3255
|
-
# if not. The mapping must be per table, so create sub maps for each table
|
|
3256
|
-
# alias.
|
|
3257
|
-
records_map = {@master=>{}}
|
|
3258
|
-
alias_map.keys.each{|ta| records_map[ta] = {}}
|
|
3259
|
-
@records_map = records_map
|
|
3260
|
-
|
|
3261
3569
|
datasets = opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
|
|
3262
3570
|
column_aliases = opts[:graph][:column_aliases]
|
|
3263
3571
|
primary_keys = {}
|
|
@@ -3283,9 +3591,9 @@ module Sequel
|
|
|
3283
3591
|
h.select{|ca, c| primary_keys[ta] = ca if pk == c}
|
|
3284
3592
|
end
|
|
3285
3593
|
end
|
|
3286
|
-
@column_maps = column_maps
|
|
3287
|
-
@primary_keys = primary_keys
|
|
3288
|
-
@row_procs = row_procs
|
|
3594
|
+
@column_maps = column_maps.freeze
|
|
3595
|
+
@primary_keys = primary_keys.freeze
|
|
3596
|
+
@row_procs = row_procs.freeze
|
|
3289
3597
|
|
|
3290
3598
|
# For performance, create two special maps for the master table,
|
|
3291
3599
|
# so you can skip a hash lookup.
|
|
@@ -3297,22 +3605,35 @@ module Sequel
|
|
|
3297
3605
|
# used for performance, to get all values in one hash lookup instead of
|
|
3298
3606
|
# separate hash lookups for each data structure.
|
|
3299
3607
|
ta_map = {}
|
|
3300
|
-
alias_map.
|
|
3301
|
-
ta_map[ta] = [
|
|
3608
|
+
alias_map.each_key do |ta|
|
|
3609
|
+
ta_map[ta] = [row_procs[ta], alias_map[ta], type_map[ta], reciprocal_map[ta]].freeze
|
|
3302
3610
|
end
|
|
3303
|
-
@ta_map = ta_map
|
|
3611
|
+
@ta_map = ta_map.freeze
|
|
3612
|
+
freeze
|
|
3304
3613
|
end
|
|
3305
3614
|
|
|
3306
3615
|
# Return an array of primary model instances with the associations cache prepopulated
|
|
3307
3616
|
# for all model objects (both primary and associated).
|
|
3308
3617
|
def load(hashes)
|
|
3618
|
+
# This mapping is used to make sure that duplicate entries in the
|
|
3619
|
+
# result set are mapped to a single record. For example, using a
|
|
3620
|
+
# single one_to_many association with 10 associated records,
|
|
3621
|
+
# the main object column values appear in the object graph 10 times.
|
|
3622
|
+
# We map by primary key, if available, or by the object's entire values,
|
|
3623
|
+
# if not. The mapping must be per table, so create sub maps for each table
|
|
3624
|
+
# alias.
|
|
3625
|
+
@records_map = records_map = {}
|
|
3626
|
+
alias_map.keys.each{|ta| records_map[ta] = {}}
|
|
3627
|
+
|
|
3309
3628
|
master = master()
|
|
3310
3629
|
|
|
3311
3630
|
# Assign to local variables for speed increase
|
|
3312
3631
|
rp = row_procs[master]
|
|
3313
|
-
rm = records_map[master]
|
|
3632
|
+
rm = records_map[master] = {}
|
|
3314
3633
|
dm = dependency_map
|
|
3315
3634
|
|
|
3635
|
+
records_map.freeze
|
|
3636
|
+
|
|
3316
3637
|
# This will hold the final record set that we will be replacing the object graph with.
|
|
3317
3638
|
records = []
|
|
3318
3639
|
|
|
@@ -3333,6 +3654,9 @@ module Sequel
|
|
|
3333
3654
|
# Run after_load procs if there are any
|
|
3334
3655
|
post_process(records, dm) if @unique || !after_load_map.empty? || !limit_map.empty?
|
|
3335
3656
|
|
|
3657
|
+
records_map.each_value(&:freeze)
|
|
3658
|
+
freeze
|
|
3659
|
+
|
|
3336
3660
|
records
|
|
3337
3661
|
end
|
|
3338
3662
|
|
|
@@ -3352,7 +3676,17 @@ module Sequel
|
|
|
3352
3676
|
end
|
|
3353
3677
|
key = hkey(ta_h)
|
|
3354
3678
|
end
|
|
3355
|
-
|
|
3679
|
+
rp, assoc_name, tm, rcm = @ta_map[ta]
|
|
3680
|
+
rm = records_map[ta]
|
|
3681
|
+
|
|
3682
|
+
# Check type map for all dependencies, and use a unique
|
|
3683
|
+
# object if any are dependencies for multiple objects,
|
|
3684
|
+
# to prevent duplicate objects from showing up in the case
|
|
3685
|
+
# the normal duplicate removal code is not being used.
|
|
3686
|
+
if !@unique && !deps.empty? && deps.any?{|dep_key,_| @ta_map[dep_key][2]}
|
|
3687
|
+
key = [current.object_id, key]
|
|
3688
|
+
end
|
|
3689
|
+
|
|
3356
3690
|
unless rec = rm[key]
|
|
3357
3691
|
rec = rm[key] = rp.call(hfor(ta, h))
|
|
3358
3692
|
end
|