sequel 3.48.0 → 4.0.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 +114 -0
- data/Rakefile +10 -7
- data/doc/association_basics.rdoc +25 -23
- data/doc/code_order.rdoc +7 -0
- data/doc/core_extensions.rdoc +0 -10
- data/doc/object_model.rdoc +4 -1
- data/doc/querying.rdoc +3 -3
- data/doc/release_notes/4.0.0.txt +262 -0
- data/doc/security.rdoc +0 -28
- data/doc/testing.rdoc +8 -14
- data/lib/sequel/adapters/ado.rb +7 -11
- data/lib/sequel/adapters/ado/access.rb +8 -8
- data/lib/sequel/adapters/ado/mssql.rb +4 -4
- data/lib/sequel/adapters/amalgalite.rb +6 -6
- data/lib/sequel/adapters/cubrid.rb +7 -7
- data/lib/sequel/adapters/db2.rb +5 -9
- data/lib/sequel/adapters/dbi.rb +2 -6
- data/lib/sequel/adapters/do.rb +4 -4
- data/lib/sequel/adapters/firebird.rb +4 -4
- data/lib/sequel/adapters/ibmdb.rb +8 -8
- data/lib/sequel/adapters/informix.rb +2 -10
- data/lib/sequel/adapters/jdbc.rb +17 -17
- data/lib/sequel/adapters/jdbc/as400.rb +2 -2
- data/lib/sequel/adapters/jdbc/cubrid.rb +1 -1
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
- data/lib/sequel/adapters/jdbc/informix.rb +1 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +5 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -3
- data/lib/sequel/adapters/jdbc/sqlite.rb +3 -3
- data/lib/sequel/adapters/jdbc/transactions.rb +3 -3
- data/lib/sequel/adapters/mock.rb +7 -7
- data/lib/sequel/adapters/mysql.rb +3 -3
- data/lib/sequel/adapters/mysql2.rb +4 -4
- data/lib/sequel/adapters/odbc.rb +2 -6
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -5
- data/lib/sequel/adapters/oracle.rb +13 -17
- data/lib/sequel/adapters/postgres.rb +20 -25
- data/lib/sequel/adapters/shared/cubrid.rb +3 -3
- data/lib/sequel/adapters/shared/db2.rb +2 -2
- data/lib/sequel/adapters/shared/firebird.rb +7 -7
- data/lib/sequel/adapters/shared/mssql.rb +9 -9
- data/lib/sequel/adapters/shared/mysql.rb +29 -13
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +7 -7
- data/lib/sequel/adapters/shared/oracle.rb +22 -13
- data/lib/sequel/adapters/shared/postgres.rb +61 -46
- data/lib/sequel/adapters/shared/sqlite.rb +9 -9
- data/lib/sequel/adapters/sqlite.rb +17 -11
- data/lib/sequel/adapters/swift.rb +3 -3
- data/lib/sequel/adapters/swift/mysql.rb +1 -1
- data/lib/sequel/adapters/swift/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +8 -8
- data/lib/sequel/ast_transformer.rb +3 -1
- data/lib/sequel/connection_pool.rb +4 -2
- data/lib/sequel/connection_pool/sharded_single.rb +2 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -5
- data/lib/sequel/connection_pool/threaded.rb +7 -7
- data/lib/sequel/core.rb +4 -67
- data/lib/sequel/database.rb +1 -0
- data/lib/sequel/database/connecting.rb +2 -8
- data/lib/sequel/database/dataset.rb +2 -7
- data/lib/sequel/database/dataset_defaults.rb +0 -18
- data/lib/sequel/database/features.rb +4 -4
- data/lib/sequel/database/misc.rb +6 -8
- data/lib/sequel/database/query.rb +5 -61
- data/lib/sequel/database/schema_generator.rb +22 -20
- data/lib/sequel/database/schema_methods.rb +48 -20
- data/lib/sequel/database/transactions.rb +7 -17
- data/lib/sequel/dataset.rb +2 -0
- data/lib/sequel/dataset/actions.rb +23 -91
- data/lib/sequel/dataset/features.rb +1 -4
- data/lib/sequel/dataset/graph.rb +3 -47
- data/lib/sequel/dataset/misc.rb +4 -33
- data/lib/sequel/dataset/prepared_statements.rb +3 -1
- data/lib/sequel/dataset/query.rb +116 -240
- data/lib/sequel/dataset/sql.rb +19 -97
- data/lib/sequel/deprecated.rb +0 -16
- data/lib/sequel/exceptions.rb +0 -3
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/columns_introspection.rb +1 -12
- data/lib/sequel/extensions/constraint_validations.rb +3 -3
- data/lib/sequel/extensions/core_extensions.rb +0 -9
- data/lib/sequel/extensions/date_arithmetic.rb +1 -2
- data/lib/sequel/extensions/graph_each.rb +11 -0
- data/lib/sequel/extensions/migration.rb +5 -5
- data/lib/sequel/extensions/null_dataset.rb +11 -13
- data/lib/sequel/extensions/pagination.rb +3 -6
- data/lib/sequel/extensions/pg_array.rb +6 -4
- data/lib/sequel/extensions/pg_array_ops.rb +35 -1
- data/lib/sequel/extensions/pg_json.rb +12 -2
- data/lib/sequel/extensions/pg_json_ops.rb +266 -0
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_range_ops.rb +0 -8
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pretty_table.rb +0 -4
- data/lib/sequel/extensions/query.rb +3 -8
- data/lib/sequel/extensions/schema_caching.rb +0 -7
- data/lib/sequel/extensions/schema_dumper.rb +10 -17
- data/lib/sequel/extensions/select_remove.rb +0 -4
- data/lib/sequel/extensions/set_overrides.rb +28 -0
- data/lib/sequel/extensions/to_dot.rb +6 -10
- data/lib/sequel/model.rb +6 -7
- data/lib/sequel/model/associations.rb +127 -182
- data/lib/sequel/model/base.rb +88 -211
- data/lib/sequel/model/errors.rb +0 -13
- data/lib/sequel/model/plugins.rb +2 -2
- data/lib/sequel/no_core_ext.rb +0 -1
- data/lib/sequel/plugins/after_initialize.rb +11 -17
- data/lib/sequel/plugins/association_autoreloading.rb +1 -47
- data/lib/sequel/plugins/association_dependencies.rb +2 -2
- data/lib/sequel/plugins/auto_validations.rb +2 -8
- data/lib/sequel/plugins/blacklist_security.rb +32 -2
- data/lib/sequel/plugins/caching.rb +1 -1
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/composition.rb +10 -8
- data/lib/sequel/plugins/constraint_validations.rb +2 -2
- data/lib/sequel/plugins/dataset_associations.rb +4 -0
- data/lib/sequel/plugins/defaults_setter.rb +8 -6
- data/lib/sequel/plugins/dirty.rb +6 -6
- data/lib/sequel/plugins/force_encoding.rb +13 -8
- data/lib/sequel/plugins/hook_class_methods.rb +1 -7
- data/lib/sequel/plugins/json_serializer.rb +13 -74
- data/lib/sequel/plugins/lazy_attributes.rb +2 -4
- data/lib/sequel/plugins/list.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +4 -11
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +1 -49
- data/lib/sequel/plugins/nested_attributes.rb +1 -1
- data/lib/sequel/plugins/optimistic_locking.rb +3 -5
- data/lib/sequel/plugins/pg_array_associations.rb +453 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +23 -7
- data/lib/sequel/plugins/prepared_statements.rb +1 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +20 -14
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -2
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +5 -4
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +7 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +2 -2
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +19 -4
- data/lib/sequel/plugins/validation_class_methods.rb +0 -30
- data/lib/sequel/plugins/validation_helpers.rb +13 -31
- data/lib/sequel/plugins/xml_serializer.rb +18 -57
- data/lib/sequel/sql.rb +20 -22
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/db2_spec.rb +14 -23
- data/spec/adapters/firebird_spec.rb +25 -29
- data/spec/adapters/informix_spec.rb +11 -14
- data/spec/adapters/mssql_spec.rb +71 -77
- data/spec/adapters/mysql_spec.rb +165 -172
- data/spec/adapters/oracle_spec.rb +36 -39
- data/spec/adapters/postgres_spec.rb +175 -100
- data/spec/adapters/spec_helper.rb +13 -11
- data/spec/adapters/sqlite_spec.rb +36 -44
- data/spec/core/connection_pool_spec.rb +2 -1
- data/spec/core/database_spec.rb +55 -55
- data/spec/core/dataset_spec.rb +45 -249
- data/spec/core/deprecated_spec.rb +0 -8
- data/spec/core/expression_filters_spec.rb +23 -5
- data/spec/core/object_graph_spec.rb +4 -66
- data/spec/core/schema_spec.rb +35 -12
- data/spec/core/spec_helper.rb +3 -2
- data/spec/core_extensions_spec.rb +17 -19
- data/spec/extensions/arbitrary_servers_spec.rb +2 -3
- data/spec/extensions/association_dependencies_spec.rb +14 -14
- data/spec/extensions/auto_validations_spec.rb +7 -0
- data/spec/extensions/blacklist_security_spec.rb +5 -5
- data/spec/extensions/blank_spec.rb +2 -0
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/extensions/columns_introspection_spec.rb +2 -29
- data/spec/extensions/composition_spec.rb +10 -17
- data/spec/extensions/core_refinements_spec.rb +5 -1
- data/spec/extensions/dataset_associations_spec.rb +18 -0
- data/spec/extensions/date_arithmetic_spec.rb +2 -2
- data/spec/extensions/defaults_setter_spec.rb +9 -9
- data/spec/extensions/dirty_spec.rb +0 -5
- data/spec/extensions/eval_inspect_spec.rb +2 -0
- data/spec/extensions/force_encoding_spec.rb +2 -18
- data/spec/extensions/hash_aliases_spec.rb +8 -0
- data/spec/extensions/hook_class_methods_spec.rb +39 -58
- data/spec/extensions/inflector_spec.rb +2 -0
- data/spec/extensions/instance_filters_spec.rb +8 -8
- data/spec/extensions/json_serializer_spec.rb +1 -41
- data/spec/extensions/list_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +106 -109
- data/spec/extensions/migration_spec.rb +2 -0
- data/spec/extensions/named_timezones_spec.rb +1 -0
- data/spec/extensions/pg_array_associations_spec.rb +603 -0
- data/spec/extensions/pg_array_ops_spec.rb +25 -0
- data/spec/extensions/pg_array_spec.rb +9 -1
- data/spec/extensions/pg_hstore_ops_spec.rb +13 -0
- data/spec/extensions/pg_hstore_spec.rb +1 -0
- data/spec/extensions/pg_json_ops_spec.rb +131 -0
- data/spec/extensions/pg_json_spec.rb +10 -4
- data/spec/extensions/pg_range_ops_spec.rb +2 -5
- data/spec/extensions/pg_range_spec.rb +6 -2
- data/spec/extensions/pg_row_ops_spec.rb +2 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +26 -5
- data/spec/extensions/rcte_tree_spec.rb +15 -15
- data/spec/extensions/schema_dumper_spec.rb +0 -1
- data/spec/extensions/schema_spec.rb +9 -9
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +18 -29
- data/spec/extensions/set_overrides_spec.rb +4 -0
- data/spec/extensions/{many_to_one_pk_lookup_spec.rb → shared_caching_spec.rb} +1 -4
- data/spec/extensions/single_table_inheritance_spec.rb +4 -4
- data/spec/extensions/spec_helper.rb +8 -9
- data/spec/extensions/sql_expr_spec.rb +2 -0
- data/spec/extensions/string_date_time_spec.rb +2 -0
- data/spec/extensions/string_stripper_spec.rb +2 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +12 -12
- data/spec/extensions/thread_local_timezones_spec.rb +2 -0
- data/spec/extensions/timestamps_spec.rb +1 -1
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +24 -24
- data/spec/extensions/tree_spec.rb +7 -7
- data/spec/extensions/typecast_on_load_spec.rb +8 -1
- data/spec/extensions/update_primary_key_spec.rb +10 -10
- data/spec/extensions/validation_class_methods_spec.rb +10 -39
- data/spec/extensions/validation_helpers_spec.rb +29 -47
- data/spec/extensions/xml_serializer_spec.rb +1 -23
- data/spec/integration/associations_test.rb +231 -40
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +64 -64
- data/spec/integration/eager_loader_test.rb +28 -28
- data/spec/integration/migrator_test.rb +1 -1
- data/spec/integration/model_test.rb +2 -2
- data/spec/integration/plugin_test.rb +21 -21
- data/spec/integration/prepared_statement_test.rb +7 -7
- data/spec/integration/schema_test.rb +115 -110
- data/spec/integration/spec_helper.rb +17 -27
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +10 -10
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/association_reflection_spec.rb +2 -28
- data/spec/model/associations_spec.rb +239 -188
- data/spec/model/base_spec.rb +27 -68
- data/spec/model/dataset_methods_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +160 -172
- data/spec/model/hooks_spec.rb +62 -79
- data/spec/model/model_spec.rb +36 -51
- data/spec/model/plugins_spec.rb +5 -19
- data/spec/model/record_spec.rb +125 -151
- data/spec/model/spec_helper.rb +8 -6
- data/spec/model/validations_spec.rb +4 -17
- data/spec/spec_config.rb +2 -10
- metadata +50 -56
- data/lib/sequel/deprecated_core_extensions.rb +0 -135
- data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -185
- data/lib/sequel/extensions/pg_statement_cache.rb +0 -318
- data/lib/sequel/plugins/identity_map.rb +0 -260
- data/lib/sequel_core.rb +0 -2
- data/lib/sequel_model.rb +0 -2
- data/spec/extensions/association_autoreloading_spec.rb +0 -102
- data/spec/extensions/identity_map_spec.rb +0 -337
- data/spec/extensions/pg_auto_parameterize_spec.rb +0 -70
- data/spec/extensions/pg_statement_cache_spec.rb +0 -208
- data/spec/rcov.opts +0 -8
- data/spec/spec_config.rb.example +0 -10
|
@@ -17,20 +17,14 @@ module Sequel
|
|
|
17
17
|
def self.extended(db)
|
|
18
18
|
db.extend_datasets(DatasetQuery)
|
|
19
19
|
end
|
|
20
|
-
end
|
|
21
20
|
|
|
22
|
-
class Database
|
|
23
21
|
# Return a dataset modified by the query block
|
|
24
22
|
def query(&block)
|
|
25
|
-
Sequel::Deprecation.deprecate('Loading the query extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(DatabaseQuery)
|
|
26
23
|
dataset.query(&block)
|
|
27
24
|
end
|
|
28
25
|
end
|
|
29
26
|
|
|
30
27
|
module DatasetQuery
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
class Dataset
|
|
34
28
|
# Translates a query block into a dataset. Query blocks are an
|
|
35
29
|
# alternative to Sequel's usual method chaining, by using
|
|
36
30
|
# instance_eval with a proxy object:
|
|
@@ -45,12 +39,13 @@ module Sequel
|
|
|
45
39
|
#
|
|
46
40
|
# dataset = DB[:items].select(:x, :y, :z).filter{(x > 1) & (y > 2)}.reverse(:z)
|
|
47
41
|
def query(&block)
|
|
48
|
-
|
|
49
|
-
query = Query.new(self)
|
|
42
|
+
query = Dataset::Query.new(self)
|
|
50
43
|
query.instance_eval(&block)
|
|
51
44
|
query.dataset
|
|
52
45
|
end
|
|
46
|
+
end
|
|
53
47
|
|
|
48
|
+
class Dataset
|
|
54
49
|
# Proxy object used by Dataset#query.
|
|
55
50
|
class Query < Sequel::BasicObject
|
|
56
51
|
# The current dataset in the query. This changes on each method call.
|
|
@@ -44,12 +44,8 @@
|
|
|
44
44
|
|
|
45
45
|
module Sequel
|
|
46
46
|
module SchemaCaching
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
class Database
|
|
50
47
|
# Dump the cached schema to the filename given in Marshal format.
|
|
51
48
|
def dump_schema_cache(file)
|
|
52
|
-
Sequel::Deprecation.deprecate('Loading the schema_caching extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaCaching)
|
|
53
49
|
File.open(file, 'wb'){|f| f.write(Marshal.dump(@schemas))}
|
|
54
50
|
nil
|
|
55
51
|
end
|
|
@@ -57,14 +53,12 @@ module Sequel
|
|
|
57
53
|
# Dump the cached schema to the filename given unless the file
|
|
58
54
|
# already exists.
|
|
59
55
|
def dump_schema_cache?(file)
|
|
60
|
-
Sequel::Deprecation.deprecate('Loading the schema_caching extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaCaching)
|
|
61
56
|
dump_schema_cache(file) unless File.exist?(file)
|
|
62
57
|
end
|
|
63
58
|
|
|
64
59
|
# Replace the schema cache with the data from the given file, which
|
|
65
60
|
# should be in Marshal format.
|
|
66
61
|
def load_schema_cache(file)
|
|
67
|
-
Sequel::Deprecation.deprecate('Loading the schema_caching extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaCaching)
|
|
68
62
|
@schemas = Marshal.load(File.read(file))
|
|
69
63
|
nil
|
|
70
64
|
end
|
|
@@ -72,7 +66,6 @@ module Sequel
|
|
|
72
66
|
# Replace the schema cache with the data from the given file if the
|
|
73
67
|
# file exists.
|
|
74
68
|
def load_schema_cache?(file)
|
|
75
|
-
Sequel::Deprecation.deprecate('Loading the schema_caching extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaCaching)
|
|
76
69
|
load_schema_cache(file) if File.exist?(file)
|
|
77
70
|
end
|
|
78
71
|
end
|
|
@@ -12,9 +12,6 @@ Sequel.extension :eval_inspect
|
|
|
12
12
|
|
|
13
13
|
module Sequel
|
|
14
14
|
module SchemaDumper
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
class Database
|
|
18
15
|
# Dump foreign key constraints for all tables as a migration. This complements
|
|
19
16
|
# the :foreign_keys=>false option to dump_schema_migration. This only dumps
|
|
20
17
|
# the constraints (not the columns) using alter_table/add_foreign_key with an
|
|
@@ -22,8 +19,7 @@ module Sequel
|
|
|
22
19
|
#
|
|
23
20
|
# Note that the migration this produces does not have a down
|
|
24
21
|
# block, so you cannot reverse it.
|
|
25
|
-
def dump_foreign_key_migration(options=
|
|
26
|
-
Sequel::Deprecation.deprecate('Loading the schema_dumper extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaDumper)
|
|
22
|
+
def dump_foreign_key_migration(options=OPTS)
|
|
27
23
|
ts = tables(options)
|
|
28
24
|
<<END_MIG
|
|
29
25
|
Sequel.migration do
|
|
@@ -41,8 +37,7 @@ END_MIG
|
|
|
41
37
|
# :index_names :: If set to false, don't record names of indexes. If
|
|
42
38
|
# set to :namespace, prepend the table name to the index name if the
|
|
43
39
|
# database does not use a global index namespace.
|
|
44
|
-
def dump_indexes_migration(options=
|
|
45
|
-
Sequel::Deprecation.deprecate('Loading the schema_dumper extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaDumper)
|
|
40
|
+
def dump_indexes_migration(options=OPTS)
|
|
46
41
|
ts = tables(options)
|
|
47
42
|
<<END_MIG
|
|
48
43
|
Sequel.migration do
|
|
@@ -66,8 +61,7 @@ END_MIG
|
|
|
66
61
|
# later via #dump_index_migration).
|
|
67
62
|
# :index_names :: If set to false, don't record names of indexes. If
|
|
68
63
|
# set to :namespace, prepend the table name to the index name.
|
|
69
|
-
def dump_schema_migration(options=
|
|
70
|
-
Sequel::Deprecation.deprecate('Loading the schema_dumper extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaDumper)
|
|
64
|
+
def dump_schema_migration(options=OPTS)
|
|
71
65
|
options = options.dup
|
|
72
66
|
if options[:indexes] == false && !options.has_key?(:foreign_keys)
|
|
73
67
|
# Unless foreign_keys option is specifically set, disable if indexes
|
|
@@ -96,8 +90,7 @@ END_MIG
|
|
|
96
90
|
|
|
97
91
|
# Return a string with a create table block that will recreate the given
|
|
98
92
|
# table's schema. Takes the same options as dump_schema_migration.
|
|
99
|
-
def dump_table_schema(table, options=
|
|
100
|
-
Sequel::Deprecation.deprecate('Loading the schema_dumper extension globally', "Please use Database#extension to load the extension into this database") unless is_a?(SchemaDumper)
|
|
93
|
+
def dump_table_schema(table, options=OPTS)
|
|
101
94
|
table = table.value.to_s if table.is_a?(SQL::Identifier)
|
|
102
95
|
gen = dump_table_generator(table, options)
|
|
103
96
|
commands = [gen.dump_columns, gen.dump_constraints, gen.dump_indexes].reject{|x| x == ''}.join("\n\n")
|
|
@@ -215,7 +208,7 @@ END_MIG
|
|
|
215
208
|
|
|
216
209
|
# For the table given, get the list of foreign keys and return an alter_table
|
|
217
210
|
# string that would add the foreign keys if run in a migration.
|
|
218
|
-
def dump_table_foreign_keys(table, options=
|
|
211
|
+
def dump_table_foreign_keys(table, options=OPTS)
|
|
219
212
|
if supports_foreign_key_parsing?
|
|
220
213
|
fks = foreign_key_list(table, options).sort_by{|fk| fk[:columns].map{|c| c.to_s}}
|
|
221
214
|
end
|
|
@@ -229,7 +222,7 @@ END_MIG
|
|
|
229
222
|
|
|
230
223
|
# Return a Schema::Generator object that will recreate the
|
|
231
224
|
# table's schema. Takes the same options as dump_schema_migration.
|
|
232
|
-
def dump_table_generator(table, options=
|
|
225
|
+
def dump_table_generator(table, options=OPTS)
|
|
233
226
|
table = table.value.to_s if table.is_a?(SQL::Identifier)
|
|
234
227
|
raise(Error, "must provide table as a Symbol, String, or Sequel::SQL::Identifier") unless [String, Symbol].any?{|c| table.is_a?(c)}
|
|
235
228
|
s = schema(table).dup
|
|
@@ -277,7 +270,7 @@ END_MIG
|
|
|
277
270
|
|
|
278
271
|
# Return a string that containing add_index/drop_index method calls for
|
|
279
272
|
# creating the index migration.
|
|
280
|
-
def dump_table_indexes(table, meth, options=
|
|
273
|
+
def dump_table_indexes(table, meth, options=OPTS)
|
|
281
274
|
if supports_index_parsing?
|
|
282
275
|
indexes = indexes(table).sort_by{|k,v| k.to_s}
|
|
283
276
|
else
|
|
@@ -292,7 +285,7 @@ END_MIG
|
|
|
292
285
|
end
|
|
293
286
|
|
|
294
287
|
# Convert the parsed index information into options to the Generators index method.
|
|
295
|
-
def index_to_generator_opts(table, name, index_opts, options=
|
|
288
|
+
def index_to_generator_opts(table, name, index_opts, options=OPTS)
|
|
296
289
|
h = {}
|
|
297
290
|
if options[:index_names] != false && default_index_name(table, index_opts[:columns]) != name.to_s
|
|
298
291
|
if options[:index_names] == :namespace && !global_index_namespace?
|
|
@@ -308,7 +301,7 @@ END_MIG
|
|
|
308
301
|
|
|
309
302
|
# Sort the tables so that referenced tables are created before tables that
|
|
310
303
|
# reference them, and then by name. If foreign keys are disabled, just sort by name.
|
|
311
|
-
def sort_dumped_tables(tables, options=
|
|
304
|
+
def sort_dumped_tables(tables, options=OPTS)
|
|
312
305
|
if options[:foreign_keys] != false && supports_foreign_key_parsing?
|
|
313
306
|
table_fks = {}
|
|
314
307
|
tables.each{|t| table_fks[t] = foreign_key_list(t)}
|
|
@@ -440,7 +433,7 @@ END_MIG
|
|
|
440
433
|
# The value of this option should be the table name to use.
|
|
441
434
|
# * :drop_index - Same as add_index, but create drop_index statements.
|
|
442
435
|
# * :ignore_errors - Add the ignore_errors option to the outputted indexes
|
|
443
|
-
def dump_indexes(options=
|
|
436
|
+
def dump_indexes(options=OPTS)
|
|
444
437
|
is = indexes.map do |c|
|
|
445
438
|
c = c.dup
|
|
446
439
|
cols = c.delete(:columns)
|
|
@@ -14,9 +14,6 @@
|
|
|
14
14
|
|
|
15
15
|
module Sequel
|
|
16
16
|
module SelectRemove
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class Dataset
|
|
20
17
|
# Remove columns from the list of selected columns. If any of the currently selected
|
|
21
18
|
# columns use expressions/aliases, this will remove selected columns with the given
|
|
22
19
|
# aliases. It will also remove entries from the selection that match exactly:
|
|
@@ -38,7 +35,6 @@ module Sequel
|
|
|
38
35
|
#
|
|
39
36
|
# There may be other cases where this method does not work correctly, use it with caution.
|
|
40
37
|
def select_remove(*cols)
|
|
41
|
-
Sequel::Deprecation.deprecate('Loading the select_remove extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(SelectRemove)
|
|
42
38
|
if (sel = @opts[:select]) && !sel.empty?
|
|
43
39
|
select(*(columns.zip(sel).reject{|c, s| cols.include?(c)}.map{|c, s| s} - cols))
|
|
44
40
|
else
|
|
@@ -16,8 +16,18 @@
|
|
|
16
16
|
|
|
17
17
|
module Sequel
|
|
18
18
|
module SetOverrides
|
|
19
|
+
Dataset::NON_SQL_OPTIONS.concat([:defaults, :overrides])
|
|
19
20
|
Dataset.def_mutation_method(:set_defaults, :set_overrides, :module=>self)
|
|
20
21
|
|
|
22
|
+
# Set overrides/defaults for insert hashes
|
|
23
|
+
def insert_sql(*values)
|
|
24
|
+
if values.size == 1 && (vals = values.first).is_a?(Hash)
|
|
25
|
+
super(merge_defaults_overrides(vals))
|
|
26
|
+
else
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
21
31
|
# Set the default values for insert and update statements. The values hash passed
|
|
22
32
|
# to insert or update are merged into this hash, so any values in the hash passed
|
|
23
33
|
# to insert or update will override values passed to this method.
|
|
@@ -37,6 +47,24 @@ module Sequel
|
|
|
37
47
|
def set_overrides(hash)
|
|
38
48
|
clone(:overrides=>hash.merge(@opts[:overrides]||{}))
|
|
39
49
|
end
|
|
50
|
+
|
|
51
|
+
# Set overrides/defaults for update hashes
|
|
52
|
+
def update_sql(values = {})
|
|
53
|
+
if values.is_a?(Hash)
|
|
54
|
+
super(merge_defaults_overrides(values))
|
|
55
|
+
else
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
# Return new hashe with merged defaults and overrides.
|
|
63
|
+
def merge_defaults_overrides(vals)
|
|
64
|
+
vals = @opts[:defaults].merge(vals) if @opts[:defaults]
|
|
65
|
+
vals = vals.merge(@opts[:overrides]) if @opts[:overrides]
|
|
66
|
+
vals
|
|
67
|
+
end
|
|
40
68
|
end
|
|
41
69
|
|
|
42
70
|
Dataset.register_extension(:set_overrides, SetOverrides)
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
module Sequel
|
|
11
11
|
class ToDot
|
|
12
12
|
module DatasetMethods
|
|
13
|
+
# Return a string that can be processed by the +dot+ program (included
|
|
14
|
+
# with graphviz) in order to see a visualization of the dataset's
|
|
15
|
+
# abstract syntax tree.
|
|
16
|
+
def to_dot
|
|
17
|
+
ToDot.output(self)
|
|
18
|
+
end
|
|
13
19
|
end
|
|
14
20
|
|
|
15
21
|
# The option keys that should be included in the dot output.
|
|
@@ -145,15 +151,5 @@ module Sequel
|
|
|
145
151
|
end
|
|
146
152
|
end
|
|
147
153
|
|
|
148
|
-
class Dataset
|
|
149
|
-
# Return a string that can be processed by the +dot+ program (included
|
|
150
|
-
# with graphviz) in order to see a visualization of the dataset's
|
|
151
|
-
# abstract syntax tree.
|
|
152
|
-
def to_dot
|
|
153
|
-
Sequel::Deprecation.deprecate('Loading the to_dot extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(ToDot::DatasetMethods)
|
|
154
|
-
ToDot.output(self)
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
154
|
Dataset.register_extension(:to_dot, ToDot::DatasetMethods)
|
|
159
155
|
end
|
data/lib/sequel/model.rb
CHANGED
|
@@ -72,6 +72,8 @@ module Sequel
|
|
|
72
72
|
# You can set the +SEQUEL_NO_ASSOCIATIONS+ constant or environment variable to
|
|
73
73
|
# make Sequel not load the associations plugin by default.
|
|
74
74
|
class Model
|
|
75
|
+
OPTS = Sequel::OPTS
|
|
76
|
+
|
|
75
77
|
# Map that stores model classes created with <tt>Sequel::Model()</tt>, to allow the reopening
|
|
76
78
|
# of classes when dealing with code reloading.
|
|
77
79
|
ANONYMOUS_MODEL_CLASSES = {}
|
|
@@ -80,9 +82,6 @@ module Sequel
|
|
|
80
82
|
DATASET_METHODS = (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS +
|
|
81
83
|
[:each_server]) - [:and, :or, :[], :[]=, :columns, :columns!, :delete, :update, :add_graph_aliases]
|
|
82
84
|
|
|
83
|
-
# Class instance variables to set to nil when a subclass is created, for -w compliance
|
|
84
|
-
EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@db]
|
|
85
|
-
|
|
86
85
|
# Boolean settings that can be modified at the global, class, or instance level.
|
|
87
86
|
BOOLEAN_SETTINGS = [:typecast_empty_string_to_nil, :typecast_on_assignment, :strict_param_setting, \
|
|
88
87
|
:raise_on_save_failure, :raise_on_typecast_failure, :require_modification, :use_after_commit_rollback, :use_transactions]
|
|
@@ -94,7 +93,7 @@ module Sequel
|
|
|
94
93
|
|
|
95
94
|
# Hooks that are called after an action. When overriding these, it is recommended to call
|
|
96
95
|
# +super+ on the first line of your method, so later hooks are called after earlier hooks.
|
|
97
|
-
AFTER_HOOKS = [:
|
|
96
|
+
AFTER_HOOKS = [:after_create, :after_update, :after_save, :after_destroy,
|
|
98
97
|
:after_validation, :after_commit, :after_rollback, :after_destroy_commit, :after_destroy_rollback]
|
|
99
98
|
|
|
100
99
|
# Hooks that are called around an action. If overridden, these methods must call super
|
|
@@ -120,7 +119,7 @@ module Sequel
|
|
|
120
119
|
:@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
|
|
121
120
|
:@raise_on_typecast_failure=>nil, :@plugins=>:dup, :@setter_methods=>nil,
|
|
122
121
|
:@use_after_commit_rollback=>nil, :@fast_pk_lookup_sql=>nil,
|
|
123
|
-
:@fast_instance_delete_sql=>nil,
|
|
122
|
+
:@fast_instance_delete_sql=>nil,
|
|
124
123
|
:@db=>nil, :@default_set_fields_options=>:dup}
|
|
125
124
|
|
|
126
125
|
# Regular expression that determines if a method name is normal in the sense that
|
|
@@ -137,7 +136,7 @@ module Sequel
|
|
|
137
136
|
@db_schema = nil
|
|
138
137
|
@dataset = nil
|
|
139
138
|
@dataset_method_modules = []
|
|
140
|
-
@default_eager_limit_strategy =
|
|
139
|
+
@default_eager_limit_strategy = true
|
|
141
140
|
@default_set_fields_options = {}
|
|
142
141
|
@overridable_methods_module = nil
|
|
143
142
|
@fast_pk_lookup_sql = nil
|
|
@@ -145,7 +144,7 @@ module Sequel
|
|
|
145
144
|
@plugins = []
|
|
146
145
|
@primary_key = :id
|
|
147
146
|
@raise_on_save_failure = true
|
|
148
|
-
@raise_on_typecast_failure =
|
|
147
|
+
@raise_on_typecast_failure = false
|
|
149
148
|
@require_modification = nil
|
|
150
149
|
@restrict_primary_key = true
|
|
151
150
|
@restricted_columns = nil
|
|
@@ -9,6 +9,7 @@ module Sequel
|
|
|
9
9
|
# Set an empty association reflection hash in the model
|
|
10
10
|
def self.apply(model)
|
|
11
11
|
model.instance_variable_set(:@association_reflections, {})
|
|
12
|
+
model.instance_variable_set(:@autoreloading_associations, {})
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
# AssociationReflection is a Hash subclass that keeps information on Sequel::Model associations. It
|
|
@@ -189,25 +190,14 @@ module Sequel
|
|
|
189
190
|
def reciprocal
|
|
190
191
|
cached_fetch(:reciprocal) do
|
|
191
192
|
possible_recips = []
|
|
192
|
-
fallback_recips = []
|
|
193
193
|
|
|
194
194
|
associated_class.all_association_reflections.each do |assoc_reflect|
|
|
195
195
|
if reciprocal_association?(assoc_reflect)
|
|
196
|
-
|
|
197
|
-
fallback_recips << assoc_reflect
|
|
198
|
-
else
|
|
199
|
-
possible_recips << assoc_reflect
|
|
200
|
-
end
|
|
196
|
+
possible_recips << assoc_reflect
|
|
201
197
|
end
|
|
202
198
|
end
|
|
203
199
|
|
|
204
|
-
|
|
205
|
-
if possible_recips.empty? && !fallback_recips.empty?
|
|
206
|
-
possible_recips = fallback_recips
|
|
207
|
-
Sequel::Deprecation.deprecate("All reciprocal association candidates found for #{self[:name]} association have conditions, blocks, or differing primary keys (#{possible_recips.map{|r| r[:name]}.join(', ')}). Automatic choosing of an reciprocal association with conditions or blocks is", "Please explicitly specify the reciprocal option for the #{self[:name]} association")
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
unless possible_recips.empty?
|
|
200
|
+
if possible_recips.length == 1
|
|
211
201
|
cached_set(:reciprocal_type, possible_recips.first[:type]) if reciprocal_type.is_a?(Array)
|
|
212
202
|
possible_recips.first[:name]
|
|
213
203
|
end
|
|
@@ -263,6 +253,14 @@ module Sequel
|
|
|
263
253
|
:"#{self[:name]}="
|
|
264
254
|
end
|
|
265
255
|
|
|
256
|
+
# The range used for slicing when using the :ruby eager limit strategy.
|
|
257
|
+
def slice_range
|
|
258
|
+
limit, offset = limit_and_offset
|
|
259
|
+
if limit || offset
|
|
260
|
+
(offset||0)..(limit ? (offset||0)+limit-1 : -1)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
266
264
|
private
|
|
267
265
|
|
|
268
266
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
|
|
@@ -300,14 +298,11 @@ module Sequel
|
|
|
300
298
|
end
|
|
301
299
|
end
|
|
302
300
|
|
|
303
|
-
# REMOVE40: merge into reciprocal_association?
|
|
304
|
-
def deprecated_reciprocal_association?(assoc_reflect)
|
|
305
|
-
assoc_reflect[:conditions] || assoc_reflect[:block]
|
|
306
|
-
end
|
|
307
|
-
|
|
308
301
|
def reciprocal_association?(assoc_reflect)
|
|
309
302
|
Array(reciprocal_type).include?(assoc_reflect[:type]) &&
|
|
310
|
-
assoc_reflect.associated_class == self[:model]
|
|
303
|
+
assoc_reflect.associated_class == self[:model] &&
|
|
304
|
+
assoc_reflect[:conditions].nil? &&
|
|
305
|
+
assoc_reflect[:block].nil?
|
|
311
306
|
end
|
|
312
307
|
|
|
313
308
|
# If +s+ is an array, map +s+ over the block. Otherwise, just call the
|
|
@@ -400,13 +395,8 @@ module Sequel
|
|
|
400
395
|
|
|
401
396
|
private
|
|
402
397
|
|
|
403
|
-
# REMOVE40: merge into reciprocal_association?
|
|
404
|
-
def deprecated_reciprocal_association?(assoc_reflect)
|
|
405
|
-
super || primary_key != assoc_reflect.primary_key
|
|
406
|
-
end
|
|
407
|
-
|
|
408
398
|
def reciprocal_association?(assoc_reflect)
|
|
409
|
-
super && self[:keys] == assoc_reflect[:keys]
|
|
399
|
+
super && self[:keys] == assoc_reflect[:keys] && primary_key == assoc_reflect.primary_key
|
|
410
400
|
end
|
|
411
401
|
|
|
412
402
|
# The reciprocal type of a many_to_one association is either
|
|
@@ -444,7 +434,7 @@ module Sequel
|
|
|
444
434
|
|
|
445
435
|
# The column in the current table that the key in the associated table references.
|
|
446
436
|
def primary_key
|
|
447
|
-
|
|
437
|
+
self[:primary_key]
|
|
448
438
|
end
|
|
449
439
|
|
|
450
440
|
# #primary_key qualified by the current table
|
|
@@ -475,13 +465,8 @@ module Sequel
|
|
|
475
465
|
|
|
476
466
|
private
|
|
477
467
|
|
|
478
|
-
# REMOVE40: merge into reciprocal_association?
|
|
479
|
-
def deprecated_reciprocal_association?(assoc_reflect)
|
|
480
|
-
super || primary_key != assoc_reflect.primary_key
|
|
481
|
-
end
|
|
482
|
-
|
|
483
468
|
def reciprocal_association?(assoc_reflect)
|
|
484
|
-
super && self[:keys] == assoc_reflect[:keys]
|
|
469
|
+
super && self[:keys] == assoc_reflect[:keys] && primary_key == assoc_reflect.primary_key
|
|
485
470
|
end
|
|
486
471
|
|
|
487
472
|
# The reciprocal type of a one_to_many association is a many_to_one association.
|
|
@@ -497,15 +482,18 @@ module Sequel
|
|
|
497
482
|
# support both DISTINCT ON and window functions as strategies.
|
|
498
483
|
def eager_limit_strategy
|
|
499
484
|
cached_fetch(:_eager_limit_strategy) do
|
|
500
|
-
|
|
485
|
+
offset = limit_and_offset.last
|
|
486
|
+
case s = self.fetch(:eager_limit_strategy){(self[:model].default_eager_limit_strategy || :ruby) if offset}
|
|
501
487
|
when Symbol
|
|
502
488
|
s
|
|
503
489
|
when true
|
|
504
490
|
ds = associated_class.dataset
|
|
505
|
-
if ds.supports_ordered_distinct_on?
|
|
491
|
+
if ds.supports_ordered_distinct_on? && offset.nil?
|
|
506
492
|
:distinct_on
|
|
507
493
|
elsif ds.supports_window_functions?
|
|
508
494
|
:window_function
|
|
495
|
+
else
|
|
496
|
+
:ruby
|
|
509
497
|
end
|
|
510
498
|
else
|
|
511
499
|
nil
|
|
@@ -515,7 +503,11 @@ module Sequel
|
|
|
515
503
|
|
|
516
504
|
# The limit and offset for this association (returned as a two element array).
|
|
517
505
|
def limit_and_offset
|
|
518
|
-
[
|
|
506
|
+
if (v = self[:limit]).is_a?(Array)
|
|
507
|
+
v
|
|
508
|
+
else
|
|
509
|
+
[v, nil]
|
|
510
|
+
end
|
|
519
511
|
end
|
|
520
512
|
|
|
521
513
|
# one_to_one associations return a single object, not an array
|
|
@@ -644,15 +636,12 @@ module Sequel
|
|
|
644
636
|
|
|
645
637
|
private
|
|
646
638
|
|
|
647
|
-
# REMOVE40: merge into reciprocal_association?
|
|
648
|
-
def deprecated_reciprocal_association?(assoc_reflect)
|
|
649
|
-
super || right_primary_keys != assoc_reflect[:left_primary_key_columns] || self[:left_primary_key_columns] != assoc_reflect.right_primary_keys
|
|
650
|
-
end
|
|
651
|
-
|
|
652
639
|
def reciprocal_association?(assoc_reflect)
|
|
653
640
|
super && assoc_reflect[:left_keys] == self[:right_keys] &&
|
|
654
641
|
assoc_reflect[:right_keys] == self[:left_keys] &&
|
|
655
|
-
assoc_reflect[:join_table] == self[:join_table]
|
|
642
|
+
assoc_reflect[:join_table] == self[:join_table] &&
|
|
643
|
+
right_primary_keys == assoc_reflect[:left_primary_key_columns] &&
|
|
644
|
+
self[:left_primary_key_columns] == assoc_reflect.right_primary_keys
|
|
656
645
|
end
|
|
657
646
|
|
|
658
647
|
def reciprocal_type
|
|
@@ -727,7 +716,13 @@ module Sequel
|
|
|
727
716
|
# All association reflections defined for this model (default: {}).
|
|
728
717
|
attr_reader :association_reflections
|
|
729
718
|
|
|
730
|
-
#
|
|
719
|
+
# Hash with column symbol keys and arrays of many_to_one
|
|
720
|
+
# association symbols that should be cleared when the column
|
|
721
|
+
# value changes.
|
|
722
|
+
attr_reader :autoreloading_associations
|
|
723
|
+
|
|
724
|
+
# The default :eager_limit_strategy option to use for limited or offset associations (default: true, causing Sequel
|
|
725
|
+
# to use what it considers the most appropriate strategy).
|
|
731
726
|
attr_accessor :default_eager_limit_strategy
|
|
732
727
|
|
|
733
728
|
# Array of all association reflections for this model class
|
|
@@ -823,14 +818,8 @@ module Sequel
|
|
|
823
818
|
# (the alias that was used for the current table), and possibly :eager_block (a callback
|
|
824
819
|
# proc accepting the associated dataset, for per-call customization).
|
|
825
820
|
# Should return a copy of the dataset with the association graphed into it.
|
|
826
|
-
# :eager_limit_strategy :: Determines the strategy used for enforcing limits when eager loading
|
|
827
|
-
# the +eager+ method.
|
|
828
|
-
# for *_many associations, the :ruby strategy is used by default, which still retrieves
|
|
829
|
-
# all records but slices the resulting array after the association is retrieved. You
|
|
830
|
-
# can pass a +true+ value for this option to have Sequel pick what it thinks is the best
|
|
831
|
-
# choice for the database, or specify a specific symbol to manually select a strategy.
|
|
832
|
-
# one_to_one associations support :distinct_on and :window_function.
|
|
833
|
-
# *_many associations support :ruby, and :window_function.
|
|
821
|
+
# :eager_limit_strategy :: Determines the strategy used for enforcing limits and offsets when eager loading
|
|
822
|
+
# associations via the +eager+ method.
|
|
834
823
|
# :eager_loader :: A proc to use to implement eager loading, overriding the default. Takes a single hash argument,
|
|
835
824
|
# with at least the keys: :rows, which is an array of current model instances, :associations,
|
|
836
825
|
# which is a hash of dependent associations, :self, which is the dataset doing the eager loading,
|
|
@@ -955,18 +944,9 @@ module Sequel
|
|
|
955
944
|
# object to get the foreign key values for the join table.
|
|
956
945
|
# Defaults to :right_primary_key option.
|
|
957
946
|
# :uniq :: Adds a after_load callback that makes the array of objects unique.
|
|
958
|
-
def associate(type, name, opts =
|
|
959
|
-
if opts[:one_to_one] && type == :one_to_many
|
|
960
|
-
Sequel::Deprecation.deprecate('Raising an Error when the one_to_many type uses the :one_to_one option', "Use the one_to_one associationtype")
|
|
961
|
-
raise(Error, 'one_to_many association type with :one_to_one option removed, used one_to_one association type')
|
|
962
|
-
end
|
|
947
|
+
def associate(type, name, opts = OPTS, &block)
|
|
963
948
|
raise(Error, 'invalid association type') unless assoc_class = ASSOCIATION_TYPES[type]
|
|
964
949
|
raise(Error, 'Model.associate name argument must be a symbol') unless name.is_a?(Symbol)
|
|
965
|
-
raise(Error, ':eager_loader option must have an arity of 1 or 3') if opts[:eager_loader] && ![1, 3].include?(opts[:eager_loader].arity)
|
|
966
|
-
raise(Error, ':eager_grapher option must have an arity of 1 or 3') if opts[:eager_grapher] && ![1, 3].include?(opts[:eager_grapher].arity)
|
|
967
|
-
|
|
968
|
-
Sequel::Deprecation.deprecate('The :eager_loader association option accepting 3 arguments', "Please switch to accepting a single options hash") if opts[:eager_loader] && opts[:eager_loader].arity == 3
|
|
969
|
-
Sequel::Deprecation.deprecate('The :eager_grapher association option accepting 3 arguments', "Please switch to accepting a single options hash") if opts[:eager_grapher] && opts[:eager_grapher].arity == 3
|
|
970
950
|
|
|
971
951
|
# dup early so we don't modify opts
|
|
972
952
|
orig_opts = opts.dup
|
|
@@ -1017,7 +997,7 @@ module Sequel
|
|
|
1017
997
|
end
|
|
1018
998
|
|
|
1019
999
|
# Modify and return eager loading dataset based on association options.
|
|
1020
|
-
def eager_loading_dataset(opts, ds, select, associations, eager_options=
|
|
1000
|
+
def eager_loading_dataset(opts, ds, select, associations, eager_options=OPTS)
|
|
1021
1001
|
ds = apply_association_dataset_opts(opts, ds)
|
|
1022
1002
|
ds = ds.select(*select) if select
|
|
1023
1003
|
if opts[:eager_graph]
|
|
@@ -1037,93 +1017,44 @@ module Sequel
|
|
|
1037
1017
|
end
|
|
1038
1018
|
|
|
1039
1019
|
# Shortcut for adding a many_to_many association, see #associate
|
|
1040
|
-
def many_to_many(name, opts=
|
|
1020
|
+
def many_to_many(name, opts=OPTS, &block)
|
|
1041
1021
|
associate(:many_to_many, name, opts, &block)
|
|
1042
1022
|
end
|
|
1043
1023
|
|
|
1044
1024
|
# Shortcut for adding a many_to_one association, see #associate
|
|
1045
|
-
def many_to_one(name, opts=
|
|
1025
|
+
def many_to_one(name, opts=OPTS, &block)
|
|
1046
1026
|
associate(:many_to_one, name, opts, &block)
|
|
1047
1027
|
end
|
|
1048
1028
|
|
|
1049
1029
|
# Shortcut for adding a one_to_many association, see #associate
|
|
1050
|
-
def one_to_many(name, opts=
|
|
1030
|
+
def one_to_many(name, opts=OPTS, &block)
|
|
1051
1031
|
associate(:one_to_many, name, opts, &block)
|
|
1052
1032
|
end
|
|
1053
1033
|
|
|
1054
1034
|
# Shortcut for adding a one_to_one association, see #associate.
|
|
1055
|
-
def one_to_one(name, opts=
|
|
1035
|
+
def one_to_one(name, opts=OPTS, &block)
|
|
1056
1036
|
associate(:one_to_one, name, opts, &block)
|
|
1057
1037
|
end
|
|
1058
1038
|
|
|
1059
|
-
Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@default_eager_limit_strategy=>nil)
|
|
1039
|
+
Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@autoreloading_associations=>:hash_dup, :@default_eager_limit_strategy=>nil)
|
|
1060
1040
|
Plugins.def_dataset_methods(self, [:eager, :eager_graph])
|
|
1061
1041
|
|
|
1062
1042
|
private
|
|
1063
1043
|
|
|
1064
|
-
# Use a correlated subquery to limit the results of the eager loading dataset.
|
|
1065
|
-
def apply_correlated_subquery_eager_limit_strategy(ds, opts)
|
|
1066
|
-
Sequel::Deprecation.deprecate('The correlated_subquery eager limit strategy', 'Switch to another eager limit strategy.')
|
|
1067
|
-
klass = opts.associated_class
|
|
1068
|
-
kds = klass.dataset
|
|
1069
|
-
dsa = ds.send(:dataset_alias, 1)
|
|
1070
|
-
raise Error, "can't use a correlated subquery if the associated class (#{opts.associated_class.inspect}) does not have a primary key" unless pk = klass.primary_key
|
|
1071
|
-
pka = Array(pk)
|
|
1072
|
-
raise Error, "can't use a correlated subquery if the associated class (#{opts.associated_class.inspect}) has a composite primary key and the database does not support multiple column IN" if pka.length > 1 && !ds.supports_multiple_column_in?
|
|
1073
|
-
table = kds.opts[:from]
|
|
1074
|
-
raise Error, "can't use a correlated subquery unless the associated class (#{opts.associated_class.inspect}) uses a single FROM table" unless table && table.length == 1
|
|
1075
|
-
table = table.first
|
|
1076
|
-
if order = ds.opts[:order]
|
|
1077
|
-
oproc = lambda do |x|
|
|
1078
|
-
case x
|
|
1079
|
-
when Symbol
|
|
1080
|
-
t, c, _ = ds.send(:split_symbol, x)
|
|
1081
|
-
if t && t.to_sym == table
|
|
1082
|
-
SQL::QualifiedIdentifier.new(dsa, c)
|
|
1083
|
-
else
|
|
1084
|
-
x
|
|
1085
|
-
end
|
|
1086
|
-
when SQL::QualifiedIdentifier
|
|
1087
|
-
if x.table == table
|
|
1088
|
-
SQL::QualifiedIdentifier.new(dsa, x.column)
|
|
1089
|
-
else
|
|
1090
|
-
x
|
|
1091
|
-
end
|
|
1092
|
-
when SQL::OrderedExpression
|
|
1093
|
-
SQL::OrderedExpression.new(oproc.call(x.expression), x.descending, :nulls=>x.nulls)
|
|
1094
|
-
else
|
|
1095
|
-
x
|
|
1096
|
-
end
|
|
1097
|
-
end
|
|
1098
|
-
order = order.map(&oproc)
|
|
1099
|
-
end
|
|
1100
|
-
limit, offset = opts.limit_and_offset
|
|
1101
|
-
|
|
1102
|
-
subquery = yield kds.
|
|
1103
|
-
unlimited.
|
|
1104
|
-
from(SQL::AliasedExpression.new(table, dsa)).
|
|
1105
|
-
select(*pka.map{|k| SQL::QualifiedIdentifier.new(dsa, k)}).
|
|
1106
|
-
order(*order).
|
|
1107
|
-
limit(limit, offset)
|
|
1108
|
-
|
|
1109
|
-
pk = if pk.is_a?(Array)
|
|
1110
|
-
pk.map{|k| SQL::QualifiedIdentifier.new(table, k)}
|
|
1111
|
-
else
|
|
1112
|
-
SQL::QualifiedIdentifier.new(table, pk)
|
|
1113
|
-
end
|
|
1114
|
-
ds.where(pk=>subquery)
|
|
1115
|
-
end
|
|
1116
|
-
|
|
1117
1044
|
# Use a window function to limit the results of the eager loading dataset.
|
|
1118
1045
|
def apply_window_function_eager_limit_strategy(ds, opts)
|
|
1119
1046
|
rn = ds.row_number_column
|
|
1120
1047
|
limit, offset = opts.limit_and_offset
|
|
1121
1048
|
ds = ds.unordered.select_append{row_number(:over, :partition=>opts.predicate_key, :order=>ds.opts[:order]){}.as(rn)}.from_self
|
|
1122
1049
|
ds = if opts[:type] == :one_to_one
|
|
1123
|
-
ds.where(rn => 1)
|
|
1050
|
+
ds.where(rn => offset ? offset+1 : 1)
|
|
1124
1051
|
elsif offset
|
|
1125
1052
|
offset += 1
|
|
1126
|
-
|
|
1053
|
+
if limit
|
|
1054
|
+
ds.where(rn => (offset...(offset+limit)))
|
|
1055
|
+
else
|
|
1056
|
+
ds.where{SQL::Identifier.new(rn) >= offset}
|
|
1057
|
+
end
|
|
1127
1058
|
else
|
|
1128
1059
|
ds.where{SQL::Identifier.new(rn) <= limit}
|
|
1129
1060
|
end
|
|
@@ -1131,19 +1062,19 @@ module Sequel
|
|
|
1131
1062
|
|
|
1132
1063
|
# The module to use for the association's methods. Defaults to
|
|
1133
1064
|
# the overridable_methods_module.
|
|
1134
|
-
def association_module(opts=
|
|
1065
|
+
def association_module(opts=OPTS)
|
|
1135
1066
|
opts.fetch(:methods_module, overridable_methods_module)
|
|
1136
1067
|
end
|
|
1137
1068
|
|
|
1138
1069
|
# Add a method to the module included in the class, so the method
|
|
1139
1070
|
# can be easily overridden in the class itself while allowing for
|
|
1140
1071
|
# super to be called.
|
|
1141
|
-
def association_module_def(name, opts=
|
|
1072
|
+
def association_module_def(name, opts=OPTS, &block)
|
|
1142
1073
|
association_module(opts).module_eval{define_method(name, &block)}
|
|
1143
1074
|
end
|
|
1144
1075
|
|
|
1145
1076
|
# Add a private method to the module included in the class.
|
|
1146
|
-
def association_module_private_def(name, opts=
|
|
1077
|
+
def association_module_private_def(name, opts=OPTS, &block)
|
|
1147
1078
|
association_module_def(name, opts, &block)
|
|
1148
1079
|
association_module(opts).send(:private, name)
|
|
1149
1080
|
end
|
|
@@ -1190,6 +1121,7 @@ module Sequel
|
|
|
1190
1121
|
graph_jt_conds = opts[:graph_join_table_conditions] = opts.fetch(:graph_join_table_conditions, []).to_a
|
|
1191
1122
|
opts[:graph_join_table_join_type] ||= opts[:graph_join_type]
|
|
1192
1123
|
opts[:after_load].unshift(:array_uniq!) if opts[:uniq]
|
|
1124
|
+
slice_range = opts.slice_range
|
|
1193
1125
|
opts[:dataset] ||= proc{opts.associated_dataset.inner_join(join_table, rcks.zip(opts.right_primary_keys) + opts.predicate_keys.zip(lcpks.map{|k| send(k)}), :qualify=>:deep)}
|
|
1194
1126
|
|
|
1195
1127
|
opts[:eager_loader] ||= proc do |eo|
|
|
@@ -1199,16 +1131,10 @@ module Sequel
|
|
|
1199
1131
|
r = rcks.zip(opts.right_primary_keys)
|
|
1200
1132
|
l = [[opts.predicate_key, h.keys]]
|
|
1201
1133
|
ds = model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, r + l, :qualify=>:deep), nil, eo[:associations], eo)
|
|
1202
|
-
|
|
1203
|
-
when :window_function
|
|
1134
|
+
if opts.eager_limit_strategy == :window_function
|
|
1204
1135
|
delete_rn = true
|
|
1205
1136
|
rn = ds.row_number_column
|
|
1206
1137
|
ds = apply_window_function_eager_limit_strategy(ds, opts)
|
|
1207
|
-
when :correlated_subquery
|
|
1208
|
-
ds = apply_correlated_subquery_eager_limit_strategy(ds, opts) do |xds|
|
|
1209
|
-
dsa = ds.send(:dataset_alias, 2)
|
|
1210
|
-
xds.inner_join(join_table, r + lcks.map{|k| [k, SQL::QualifiedIdentifier.new(opts.join_table_alias, k)]}, :table_alias=>dsa, :qualify=>:deep)
|
|
1211
|
-
end
|
|
1212
1138
|
end
|
|
1213
1139
|
ds.all do |assoc_record|
|
|
1214
1140
|
assoc_record.values.delete(rn) if delete_rn
|
|
@@ -1221,8 +1147,7 @@ module Sequel
|
|
|
1221
1147
|
objects.each{|object| object.associations[name].push(assoc_record)}
|
|
1222
1148
|
end
|
|
1223
1149
|
if opts.eager_limit_strategy == :ruby
|
|
1224
|
-
|
|
1225
|
-
rows.each{|o| o.associations[name] = o.associations[name].slice(offset||0, limit) || []}
|
|
1150
|
+
rows.each{|o| o.associations[name] = o.associations[name][slice_range] || []}
|
|
1226
1151
|
end
|
|
1227
1152
|
end
|
|
1228
1153
|
|
|
@@ -1285,6 +1210,17 @@ module Sequel
|
|
|
1285
1210
|
end
|
|
1286
1211
|
uses_cks = opts[:uses_composite_keys] = cks.length > 1
|
|
1287
1212
|
opts[:cartesian_product_number] ||= 0
|
|
1213
|
+
|
|
1214
|
+
if !opts.has_key?(:many_to_one_pk_lookup) &&
|
|
1215
|
+
(opts[:dataset] || opts[:conditions] || opts[:block] || opts[:select] ||
|
|
1216
|
+
(opts.has_key?(:key) && opts[:key] == nil))
|
|
1217
|
+
opts[:many_to_one_pk_lookup] = false
|
|
1218
|
+
end
|
|
1219
|
+
auto_assocs = @autoreloading_associations
|
|
1220
|
+
cks.each do |k|
|
|
1221
|
+
(auto_assocs[k] ||= []) << name
|
|
1222
|
+
end
|
|
1223
|
+
|
|
1288
1224
|
opts[:dataset] ||= proc do
|
|
1289
1225
|
opts.associated_dataset.where(opts.predicate_keys.zip(cks.map{|k| send(k)}))
|
|
1290
1226
|
end
|
|
@@ -1342,21 +1278,18 @@ module Sequel
|
|
|
1342
1278
|
pkcs = opts[:primary_key_columns] ||= Array(pkc)
|
|
1343
1279
|
raise(Error, "mismatched number of keys: #{cks.inspect} vs #{cpks.inspect}") unless cks.length == cpks.length
|
|
1344
1280
|
uses_cks = opts[:uses_composite_keys] = cks.length > 1
|
|
1281
|
+
slice_range = opts.slice_range
|
|
1345
1282
|
opts[:dataset] ||= proc do
|
|
1346
1283
|
opts.associated_dataset.where(opts.predicate_keys.zip(cpks.map{|k| send(k)}))
|
|
1347
1284
|
end
|
|
1348
1285
|
opts[:eager_loader] ||= proc do |eo|
|
|
1349
1286
|
h = eo[:id_map]
|
|
1350
1287
|
rows = eo[:rows]
|
|
1351
|
-
if one_to_one
|
|
1352
|
-
rows.each{|object| object.associations[name] = nil}
|
|
1353
|
-
else
|
|
1354
|
-
rows.each{|object| object.associations[name] = []}
|
|
1355
|
-
end
|
|
1356
1288
|
reciprocal = opts.reciprocal
|
|
1357
1289
|
klass = opts.associated_class
|
|
1358
1290
|
filter_keys = opts.predicate_key
|
|
1359
1291
|
ds = model.eager_loading_dataset(opts, klass.where(filter_keys=>h.keys), nil, eo[:associations], eo)
|
|
1292
|
+
assign_singular = true if one_to_one
|
|
1360
1293
|
case opts.eager_limit_strategy
|
|
1361
1294
|
when :distinct_on
|
|
1362
1295
|
ds = ds.distinct(*filter_keys).order_prepend(*filter_keys)
|
|
@@ -1364,16 +1297,19 @@ module Sequel
|
|
|
1364
1297
|
delete_rn = true
|
|
1365
1298
|
rn = ds.row_number_column
|
|
1366
1299
|
ds = apply_window_function_eager_limit_strategy(ds, opts)
|
|
1367
|
-
when :
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1300
|
+
when :ruby
|
|
1301
|
+
assign_singular = false if one_to_one && slice_range
|
|
1302
|
+
end
|
|
1303
|
+
if assign_singular
|
|
1304
|
+
rows.each{|object| object.associations[name] = nil}
|
|
1305
|
+
else
|
|
1306
|
+
rows.each{|object| object.associations[name] = []}
|
|
1371
1307
|
end
|
|
1372
1308
|
ds.all do |assoc_record|
|
|
1373
1309
|
assoc_record.values.delete(rn) if delete_rn
|
|
1374
1310
|
hash_key = uses_cks ? km.map{|k| assoc_record.send(k)} : assoc_record.send(km)
|
|
1375
1311
|
next unless objects = h[hash_key]
|
|
1376
|
-
if
|
|
1312
|
+
if assign_singular
|
|
1377
1313
|
objects.each do |object|
|
|
1378
1314
|
unless object.associations[name]
|
|
1379
1315
|
object.associations[name] = assoc_record
|
|
@@ -1388,8 +1324,13 @@ module Sequel
|
|
|
1388
1324
|
end
|
|
1389
1325
|
end
|
|
1390
1326
|
if opts.eager_limit_strategy == :ruby
|
|
1391
|
-
|
|
1392
|
-
|
|
1327
|
+
if one_to_one
|
|
1328
|
+
if slice_range
|
|
1329
|
+
rows.each{|o| o.associations[name] = o.associations[name][slice_range.begin]}
|
|
1330
|
+
end
|
|
1331
|
+
else
|
|
1332
|
+
rows.each{|o| o.associations[name] = o.associations[name][slice_range] || []}
|
|
1333
|
+
end
|
|
1393
1334
|
end
|
|
1394
1335
|
end
|
|
1395
1336
|
|
|
@@ -1492,20 +1433,6 @@ module Sequel
|
|
|
1492
1433
|
super
|
|
1493
1434
|
end
|
|
1494
1435
|
|
|
1495
|
-
# Clear the associations cache when refreshing
|
|
1496
|
-
def set_values(hash)
|
|
1497
|
-
@associations.clear if @associations
|
|
1498
|
-
super
|
|
1499
|
-
end
|
|
1500
|
-
|
|
1501
|
-
# Formally used internally by the associations code, like pk but doesn't raise
|
|
1502
|
-
# an Error if the model has no primary key. Not used any longer, deprecated.
|
|
1503
|
-
def pk_or_nil
|
|
1504
|
-
Sequel::Deprecation.deprecate('Model#pk_or_nil', 'There is no replacement')
|
|
1505
|
-
key = primary_key
|
|
1506
|
-
key.is_a?(Array) ? key.map{|k| @values[k]} : @values[key]
|
|
1507
|
-
end
|
|
1508
|
-
|
|
1509
1436
|
private
|
|
1510
1437
|
|
|
1511
1438
|
# Apply the association options such as :order and :limit to the given dataset, returning a modified dataset.
|
|
@@ -1559,10 +1486,12 @@ module Sequel
|
|
|
1559
1486
|
|
|
1560
1487
|
# Return the associated objects from the dataset, without association callbacks, reciprocals, and caching.
|
|
1561
1488
|
# Still apply the dynamic callback if present.
|
|
1562
|
-
def _load_associated_objects(opts, dynamic_opts=
|
|
1489
|
+
def _load_associated_objects(opts, dynamic_opts=OPTS)
|
|
1563
1490
|
if opts.can_have_associated_objects?(self)
|
|
1564
1491
|
if opts.returns_array?
|
|
1565
1492
|
_load_associated_object_array(opts, dynamic_opts)
|
|
1493
|
+
elsif load_with_primary_key_lookup?(opts, dynamic_opts)
|
|
1494
|
+
opts.associated_class.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| send(c)} : send(fk)))
|
|
1566
1495
|
else
|
|
1567
1496
|
_load_associated_object(opts, dynamic_opts)
|
|
1568
1497
|
end
|
|
@@ -1570,7 +1499,13 @@ module Sequel
|
|
|
1570
1499
|
[]
|
|
1571
1500
|
end
|
|
1572
1501
|
end
|
|
1573
|
-
|
|
1502
|
+
|
|
1503
|
+
# Clear the associations cache when refreshing
|
|
1504
|
+
def _refresh_set_values(hash)
|
|
1505
|
+
@associations.clear if @associations
|
|
1506
|
+
super
|
|
1507
|
+
end
|
|
1508
|
+
|
|
1574
1509
|
# Add the given associated object to the given association
|
|
1575
1510
|
def add_associated_object(opts, o, *args)
|
|
1576
1511
|
klass = opts.associated_class
|
|
@@ -1612,6 +1547,15 @@ module Sequel
|
|
|
1612
1547
|
a.uniq!
|
|
1613
1548
|
end
|
|
1614
1549
|
|
|
1550
|
+
# If a foreign key column value changes, clear the related
|
|
1551
|
+
# cached associations.
|
|
1552
|
+
def change_column_value(column, value)
|
|
1553
|
+
if assocs = model.autoreloading_associations[column]
|
|
1554
|
+
assocs.each{|a| associations.delete(a)}
|
|
1555
|
+
end
|
|
1556
|
+
super
|
|
1557
|
+
end
|
|
1558
|
+
|
|
1615
1559
|
# Save the associated object if the associated object needs a primary key
|
|
1616
1560
|
# and the associated object is new and does not have one. Raise an error if
|
|
1617
1561
|
# the object still does not have a primary key
|
|
@@ -1655,6 +1599,13 @@ module Sequel
|
|
|
1655
1599
|
end
|
|
1656
1600
|
end
|
|
1657
1601
|
|
|
1602
|
+
# Whether to use a simple primary key lookup on the associated class when loading.
|
|
1603
|
+
def load_with_primary_key_lookup?(opts, dynamic_opts)
|
|
1604
|
+
opts[:type] == :many_to_one &&
|
|
1605
|
+
!dynamic_opts[:callback] &&
|
|
1606
|
+
opts.send(:cached_fetch, :many_to_one_pk_lookup){opts.primary_key == opts.associated_class.primary_key}
|
|
1607
|
+
end
|
|
1608
|
+
|
|
1658
1609
|
# Remove all associated objects from the given association
|
|
1659
1610
|
def remove_all_associated_objects(opts, *args)
|
|
1660
1611
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") unless pk
|
|
@@ -1922,18 +1873,20 @@ module Sequel
|
|
|
1922
1873
|
# Like +eager+, you need to call +all+ on the dataset for the eager loading to work. If you just
|
|
1923
1874
|
# call +each+, it will yield plain hashes, each containing all columns from all the tables.
|
|
1924
1875
|
def eager_graph(*associations)
|
|
1925
|
-
|
|
1876
|
+
if eg = @opts[:eager_graph]
|
|
1926
1877
|
eg = eg.dup
|
|
1927
1878
|
[:requirements, :reflections, :reciprocals].each{|k| eg[k] = eg[k].dup}
|
|
1928
|
-
clone(:eager_graph=>eg)
|
|
1879
|
+
ds = clone(:eager_graph=>eg)
|
|
1880
|
+
ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations)
|
|
1929
1881
|
else
|
|
1930
1882
|
# Each of the following have a symbol key for the table alias, with the following values:
|
|
1931
1883
|
# :reciprocals - the reciprocal instance variable to use for this association
|
|
1932
1884
|
# :reflections - AssociationReflection instance related to this association
|
|
1933
1885
|
# :requirements - array of requirements for this association
|
|
1934
|
-
clone(:eager_graph=>{:requirements=>{}, :master=>alias_symbol(first_source), :reflections=>{}, :reciprocals=>{}, :cartesian_product_number=>0})
|
|
1886
|
+
ds = clone(:eager_graph=>{:requirements=>{}, :master=>alias_symbol(first_source), :reflections=>{}, :reciprocals=>{}, :cartesian_product_number=>0, :row_proc=>row_proc})
|
|
1887
|
+
ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations).
|
|
1888
|
+
naked
|
|
1935
1889
|
end
|
|
1936
|
-
ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations)
|
|
1937
1890
|
end
|
|
1938
1891
|
|
|
1939
1892
|
# Do not attempt to split the result set into associations,
|
|
@@ -1941,7 +1894,11 @@ module Sequel
|
|
|
1941
1894
|
# want to use eager_graph as a shortcut to have all of the joins
|
|
1942
1895
|
# and aliasing set up, but want to do something else with the dataset.
|
|
1943
1896
|
def ungraphed
|
|
1944
|
-
super.clone(:eager_graph=>nil)
|
|
1897
|
+
ds = super.clone(:eager_graph=>nil)
|
|
1898
|
+
if (eg = @opts[:eager_graph]) && (rp = eg[:row_proc])
|
|
1899
|
+
ds.row_proc = rp
|
|
1900
|
+
end
|
|
1901
|
+
ds
|
|
1945
1902
|
end
|
|
1946
1903
|
|
|
1947
1904
|
protected
|
|
@@ -1977,11 +1934,7 @@ module Sequel
|
|
|
1977
1934
|
associations = assoc.is_a?(Array) ? assoc : [assoc]
|
|
1978
1935
|
end
|
|
1979
1936
|
end
|
|
1980
|
-
ds =
|
|
1981
|
-
loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>ta, :callback=>callback)
|
|
1982
|
-
else
|
|
1983
|
-
loader.call(ds, assoc_table_alias, ta)
|
|
1984
|
-
end
|
|
1937
|
+
ds = loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>ta, :callback=>callback)
|
|
1985
1938
|
ds = ds.order_more(*qualified_expression(r[:order], assoc_table_alias)) if r[:order] and r[:order_eager_graph]
|
|
1986
1939
|
eager_graph = ds.opts[:eager_graph]
|
|
1987
1940
|
eager_graph[:requirements][assoc_table_alias] = requirements.dup
|
|
@@ -2134,20 +2087,11 @@ module Sequel
|
|
|
2134
2087
|
elsif associations.is_a?(Hash) && associations.length == 1 && (pr_assoc = associations.to_a.first) && pr_assoc.first.respond_to?(:call)
|
|
2135
2088
|
eager_block, associations = pr_assoc
|
|
2136
2089
|
end
|
|
2137
|
-
|
|
2138
|
-
loader.call(:key_hash=>key_hash, :rows=>a, :associations=>associations, :self=>self, :eager_block=>eager_block, :id_map=>id_map)
|
|
2139
|
-
else
|
|
2140
|
-
loader.call(key_hash, a, associations)
|
|
2141
|
-
end
|
|
2090
|
+
loader.call(:key_hash=>key_hash, :rows=>a, :associations=>associations, :self=>self, :eager_block=>eager_block, :id_map=>id_map)
|
|
2142
2091
|
a.each{|object| object.send(:run_association_callbacks, r, :after_load, object.associations[r[:name]])} unless r[:after_load].empty?
|
|
2143
2092
|
end
|
|
2144
2093
|
end
|
|
2145
2094
|
|
|
2146
|
-
# Return plain hashes instead of calling the row_proc if eager_graph is being used.
|
|
2147
|
-
def graph_each(&block)
|
|
2148
|
-
@opts[:eager_graph] ? fetch_rows(select_sql, &block) : super
|
|
2149
|
-
end
|
|
2150
|
-
|
|
2151
2095
|
# Return a subquery expression for filering by a many_to_many association
|
|
2152
2096
|
def many_to_many_association_filter_expression(op, ref, obj)
|
|
2153
2097
|
lpks, lks, rks = ref.values_at(:left_primary_key_columns, :left_keys, :right_keys)
|
|
@@ -2474,7 +2418,8 @@ module Sequel
|
|
|
2474
2418
|
list.uniq!
|
|
2475
2419
|
if lo = limit_map[ta]
|
|
2476
2420
|
limit, offset = lo
|
|
2477
|
-
|
|
2421
|
+
offset ||= 0
|
|
2422
|
+
list.replace(list[(offset)..(limit ? (offset)+limit-1 : -1)])
|
|
2478
2423
|
end
|
|
2479
2424
|
list
|
|
2480
2425
|
elsif list
|