sequel 3.48.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,260 +0,0 @@
|
|
1
|
-
module Sequel
|
2
|
-
module Plugins
|
3
|
-
# The identity_map plugin allows the user to create temporary identity maps
|
4
|
-
# via the with_identity_map method, which takes a block. Inside the block,
|
5
|
-
# objects have a 1-1 correspondence with rows in the database.
|
6
|
-
#
|
7
|
-
# For example, the following is true, and wouldn't be true if you weren't
|
8
|
-
# using the identity map:
|
9
|
-
# Sequel::Model.with_identity_map do
|
10
|
-
# Album.filter{(id > 0) & (id < 2)}.first.object_id == Album.first(:id=>1).object_id
|
11
|
-
# end
|
12
|
-
#
|
13
|
-
# In addition to providing a 1-1 correspondence, the identity_map plugin
|
14
|
-
# also provides a cached looked up of records in two cases:
|
15
|
-
# * Model.[] (e.g. Album[1])
|
16
|
-
# * Model.many_to_one accessor methods (e.g. album.artist)
|
17
|
-
#
|
18
|
-
# If the object you are looking up, using one of those two methods, is already
|
19
|
-
# in the identity map, the record is returned without a database query being
|
20
|
-
# issued.
|
21
|
-
#
|
22
|
-
# Identity maps are thread-local and only persist for the duration of the block,
|
23
|
-
# so they should only be considered as a possible performance enhancer.
|
24
|
-
#
|
25
|
-
# The identity_map plugin is not compatible with the eager loading in the +rcte_tree+ plugin.
|
26
|
-
#
|
27
|
-
# Usage:
|
28
|
-
#
|
29
|
-
# # Use an identity map that will affect all model classes (called before loading subclasses)
|
30
|
-
# Sequel::Model.plugin :identity_map
|
31
|
-
#
|
32
|
-
# # Use an identity map just for the Album class
|
33
|
-
# Album.plugin :identity_map
|
34
|
-
# # would need to do Album.with_identity_map{} to use the identity map
|
35
|
-
module IdentityMap
|
36
|
-
def self.apply(mod)
|
37
|
-
Sequel::Deprecation.deprecate('The identity_map plugin', 'Please stop loading it') unless defined?(SEQUEL_EXTENSIONS_NO_DEPRECATION_WARNING)
|
38
|
-
end
|
39
|
-
|
40
|
-
module ClassMethods
|
41
|
-
# Override the default :eager_loader option for many_*_many associations to work
|
42
|
-
# with an identity_map. If the :eager_graph association option is used, you'll probably have to use
|
43
|
-
# :uniq=>true on the current association and :cartesian_product_number=>2 on the association
|
44
|
-
# mentioned by :eager_graph, otherwise you'll end up with duplicates because the row proc will be
|
45
|
-
# getting called multiple times for the same object. If you do have duplicates and you use :eager_graph,
|
46
|
-
# they'll probably be lost. Making that work correctly would require changing a lot of the core
|
47
|
-
# architecture, such as how graphing and eager graphing work.
|
48
|
-
def associate(type, name, opts = {}, &block)
|
49
|
-
if opts[:eager_loader]
|
50
|
-
super
|
51
|
-
elsif type == :many_to_many
|
52
|
-
opts = super
|
53
|
-
el = opts[:eager_loader]
|
54
|
-
model = self
|
55
|
-
left_pk = opts[:left_primary_key]
|
56
|
-
uses_lcks = opts[:uses_left_composite_keys]
|
57
|
-
uses_rcks = opts[:uses_right_composite_keys]
|
58
|
-
right = opts[:right_key]
|
59
|
-
rcks = opts[:right_keys]
|
60
|
-
join_table = opts[:join_table]
|
61
|
-
left = opts[:left_key]
|
62
|
-
lcks = opts[:left_keys]
|
63
|
-
left_key_alias = opts[:left_key_alias] ||= opts.default_associated_key_alias
|
64
|
-
opts[:eager_loader] = lambda do |eo|
|
65
|
-
return el.call(eo) unless model.identity_map
|
66
|
-
h = eo[:id_map]
|
67
|
-
eo[:rows].each{|object| object.associations[name] = []}
|
68
|
-
r = uses_rcks ? rcks.zip(opts.right_primary_keys) : [[right, opts.right_primary_key]]
|
69
|
-
l = uses_lcks ? [[lcks.map{|k| SQL::QualifiedIdentifier.new(join_table, k)}, h.keys]] : [[left, h.keys]]
|
70
|
-
|
71
|
-
# Replace the row proc to remove the left key alias before calling the previous row proc.
|
72
|
-
# Associate the value of the left key alias with the associated object (through its object_id).
|
73
|
-
# When loading the associated objects, lookup the left key alias value and associate the
|
74
|
-
# associated objects to the main objects if the left key alias value matches the left primary key
|
75
|
-
# value of the main object.
|
76
|
-
#
|
77
|
-
# The deleting of the left key alias from the hash before calling the previous row proc
|
78
|
-
# is necessary when an identity map is used, otherwise if the same associated object is returned more than
|
79
|
-
# once for the association, it won't know which of current objects to associate it to.
|
80
|
-
ds = opts.associated_class.inner_join(join_table, r + l)
|
81
|
-
pr = ds.row_proc
|
82
|
-
h2 = {}
|
83
|
-
ds.row_proc = proc do |hash|
|
84
|
-
hash_key = if uses_lcks
|
85
|
-
left_key_alias.map{|k| hash.delete(k)}
|
86
|
-
else
|
87
|
-
hash.delete(left_key_alias)
|
88
|
-
end
|
89
|
-
obj = pr.call(hash)
|
90
|
-
(h2[obj.object_id] ||= []) << hash_key
|
91
|
-
obj
|
92
|
-
end
|
93
|
-
model.eager_loading_dataset(opts, ds, Array(opts.select), eo[:associations], eo) .all do |assoc_record|
|
94
|
-
if hash_keys = h2.delete(assoc_record.object_id)
|
95
|
-
hash_keys.each do |hash_key|
|
96
|
-
if objects = h[hash_key]
|
97
|
-
objects.each{|object| object.associations[name].push(assoc_record)}
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
opts
|
104
|
-
elsif type == :many_through_many
|
105
|
-
opts = super
|
106
|
-
el = opts[:eager_loader]
|
107
|
-
model = self
|
108
|
-
left_pk = opts[:left_primary_key]
|
109
|
-
left_key = opts[:left_key]
|
110
|
-
uses_lcks = opts[:uses_left_composite_keys]
|
111
|
-
left_keys = Array(left_key)
|
112
|
-
left_key_alias = opts[:left_key_alias]
|
113
|
-
opts[:eager_loader] = lambda do |eo|
|
114
|
-
return el.call(eo) unless model.identity_map
|
115
|
-
h = eo[:id_map]
|
116
|
-
eo[:rows].each{|object| object.associations[name] = []}
|
117
|
-
ds = opts.associated_class
|
118
|
-
opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
|
119
|
-
ft = opts.final_reverse_edge
|
120
|
-
conds = uses_lcks ? [[left_keys.map{|k| SQL::QualifiedIdentifier.new(ft[:table], k)}, h.keys]] : [[left_key, h.keys]]
|
121
|
-
|
122
|
-
# See above comment in many_to_many eager_loader
|
123
|
-
ds = ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + conds, :table_alias=>ft[:alias])
|
124
|
-
pr = ds.row_proc
|
125
|
-
h2 = {}
|
126
|
-
ds.row_proc = proc do |hash|
|
127
|
-
hash_key = if uses_lcks
|
128
|
-
left_key_alias.map{|k| hash.delete(k)}
|
129
|
-
else
|
130
|
-
hash.delete(left_key_alias)
|
131
|
-
end
|
132
|
-
obj = pr.call(hash)
|
133
|
-
(h2[obj.object_id] ||= []) << hash_key
|
134
|
-
obj
|
135
|
-
end
|
136
|
-
model.eager_loading_dataset(opts, ds, Array(opts.select), eo[:associations], eo).all do |assoc_record|
|
137
|
-
if hash_keys = h2.delete(assoc_record.object_id)
|
138
|
-
hash_keys.each do |hash_key|
|
139
|
-
if objects = h[hash_key]
|
140
|
-
objects.each{|object| object.associations[name].push(assoc_record)}
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
opts
|
147
|
-
else
|
148
|
-
super
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# Returns the current thread-local identity map. Should be a hash if
|
153
|
-
# there is an active identity map, and nil otherwise.
|
154
|
-
def identity_map
|
155
|
-
Thread.current[:sequel_identity_map]
|
156
|
-
end
|
157
|
-
|
158
|
-
# The identity map key for an object of the current class with the given pk.
|
159
|
-
# May not always be correct for a class which uses STI.
|
160
|
-
def identity_map_key(pk)
|
161
|
-
pk = Array(pk)
|
162
|
-
"#{self}:#{pk.join(',')}" unless pk.compact.empty?
|
163
|
-
end
|
164
|
-
|
165
|
-
# If the identity map is in use, check it for a current copy of the object.
|
166
|
-
# If a copy does not exist, create a new object and add it to the identity map.
|
167
|
-
# If a copy exists, add any values in the given row that aren't currently
|
168
|
-
# in the object to the object's values. This allows you to only request
|
169
|
-
# certain fields in an initial query, make modifications to some of those
|
170
|
-
# fields and request other, potentially overlapping fields in a new query,
|
171
|
-
# and not have the second query override fields you modified.
|
172
|
-
def call(row)
|
173
|
-
return super unless (idm = identity_map) && (pk = primary_key)
|
174
|
-
if (k = identity_map_key(Array(pk).map{|x| row[x]})) && (o = idm[k])
|
175
|
-
o.merge_db_update(row)
|
176
|
-
else
|
177
|
-
o = super
|
178
|
-
if (k = identity_map_key(o.pk))
|
179
|
-
idm[k] = o
|
180
|
-
end
|
181
|
-
end
|
182
|
-
o
|
183
|
-
end
|
184
|
-
|
185
|
-
# Take a block and inside that block use an identity map to ensure a 1-1
|
186
|
-
# correspondence of objects to the database row they represent.
|
187
|
-
def with_identity_map
|
188
|
-
return yield if identity_map
|
189
|
-
begin
|
190
|
-
self.identity_map = {}
|
191
|
-
yield
|
192
|
-
ensure
|
193
|
-
self.identity_map = nil
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
|
-
|
199
|
-
# Set the thread local identity map to the given value.
|
200
|
-
def identity_map=(v)
|
201
|
-
Thread.current[:sequel_identity_map] = v
|
202
|
-
end
|
203
|
-
|
204
|
-
# Check the current identity map if it exists for the object with
|
205
|
-
# the matching pk. If one is found, return it, otherwise call super.
|
206
|
-
def primary_key_lookup(pk)
|
207
|
-
((idm = identity_map) && (k = identity_map_key(pk)) && (o = idm[k])) ? o : super
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
module InstanceMethods
|
212
|
-
# Remove instances from the identity map cache if they are deleted.
|
213
|
-
def delete
|
214
|
-
super
|
215
|
-
if (idm = model.identity_map) && (k = model.identity_map_key(pk))
|
216
|
-
idm.delete(k)
|
217
|
-
end
|
218
|
-
self
|
219
|
-
end
|
220
|
-
|
221
|
-
# Merge the current values into the values provided in the row, ensuring
|
222
|
-
# that current values are not overridden by new values.
|
223
|
-
def merge_db_update(row)
|
224
|
-
@values = row.merge(@values)
|
225
|
-
end
|
226
|
-
|
227
|
-
private
|
228
|
-
|
229
|
-
# The primary keys values of the associated object, given the foreign
|
230
|
-
# key columns(s).
|
231
|
-
def _associated_object_pk(fk)
|
232
|
-
fk.is_a?(Array) ? fk.map{|c| send(c)} : send(fk)
|
233
|
-
end
|
234
|
-
|
235
|
-
# If the association is a many_to_one and it has a :key option and the
|
236
|
-
# key option has a value and the association uses the primary key of
|
237
|
-
# the associated class as the :primary_key option, check the identity
|
238
|
-
# map for the associated object and return it if present.
|
239
|
-
def _load_associated_object(opts, dynamic_opts)
|
240
|
-
klass = opts.associated_class
|
241
|
-
cache_lookup = opts.fetch(:idm_cache_lookup) do
|
242
|
-
opts[:idm_cache_lookup] = klass.respond_to?(:identity_map) &&
|
243
|
-
opts[:type] == :many_to_one &&
|
244
|
-
opts[:key] &&
|
245
|
-
opts.primary_key == klass.primary_key
|
246
|
-
end
|
247
|
-
if cache_lookup &&
|
248
|
-
!dynamic_opts[:callback] &&
|
249
|
-
(idm = klass.identity_map) &&
|
250
|
-
(k = klass.identity_map_key(_associated_object_pk(opts[:key]))) &&
|
251
|
-
(o = idm[k])
|
252
|
-
o
|
253
|
-
else
|
254
|
-
super
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
data/lib/sequel_core.rb
DELETED
data/lib/sequel_model.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
-
|
3
|
-
describe "AssociationAutoreloading plugin" do
|
4
|
-
before do
|
5
|
-
@c = Class.new(Sequel::Model)
|
6
|
-
@c.plugin :association_autoreloading
|
7
|
-
@Artist = Class.new(@c).set_dataset(:artists)
|
8
|
-
@Artist.dataset._fetch = {:id=>2, :name=>'Ar'}
|
9
|
-
@Album = Class.new(@c).set_dataset(:albums)
|
10
|
-
@Artist.columns :id, :name
|
11
|
-
@Album.columns :id, :name, :artist_id
|
12
|
-
@Album.db_schema[:artist_id][:type] = :integer
|
13
|
-
@Album.many_to_one :artist, :class=>@Artist
|
14
|
-
MODEL_DB.reset
|
15
|
-
end
|
16
|
-
|
17
|
-
specify "should reload many_to_one association when foreign key is modified" do
|
18
|
-
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
19
|
-
album.artist
|
20
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
|
21
|
-
|
22
|
-
album.artist_id = 1
|
23
|
-
album.artist
|
24
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
|
25
|
-
end
|
26
|
-
|
27
|
-
specify "should handle multiple many_to_one association with the same foreign key" do
|
28
|
-
@Album.many_to_one :artist2, :key=>:artist_id, :class=>@Artist
|
29
|
-
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
30
|
-
album.artist
|
31
|
-
album.artist2
|
32
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1'] * 2
|
33
|
-
|
34
|
-
album.artist
|
35
|
-
album.artist2
|
36
|
-
MODEL_DB.sqls.should == []
|
37
|
-
|
38
|
-
album.artist_id = 1
|
39
|
-
album.artist
|
40
|
-
album.artist2
|
41
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1'] * 2
|
42
|
-
end
|
43
|
-
|
44
|
-
specify "should not reload when value has not changed" do
|
45
|
-
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
46
|
-
album.artist
|
47
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
|
48
|
-
|
49
|
-
album.artist_id = 2
|
50
|
-
album.artist
|
51
|
-
MODEL_DB.sqls.should == []
|
52
|
-
|
53
|
-
album.artist_id = "2"
|
54
|
-
album.artist
|
55
|
-
MODEL_DB.sqls.should == []
|
56
|
-
end
|
57
|
-
|
58
|
-
specify "should reload all associations which use the foreign key" do
|
59
|
-
@Album.many_to_one :other_artist, :key => :artist_id, :foreign_key => :id, :class => @Artist
|
60
|
-
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
61
|
-
album.artist
|
62
|
-
album.other_artist
|
63
|
-
MODEL_DB.reset
|
64
|
-
|
65
|
-
album.artist_id = 1
|
66
|
-
album.artist
|
67
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
|
68
|
-
|
69
|
-
album.other_artist
|
70
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
|
71
|
-
end
|
72
|
-
|
73
|
-
specify "should work with composite keys" do
|
74
|
-
@Album.many_to_one :composite_artist, :key => [:artist_id, :name], :primary_key => [:id, :name], :class => @Artist
|
75
|
-
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
76
|
-
album.composite_artist
|
77
|
-
MODEL_DB.reset
|
78
|
-
|
79
|
-
album.artist_id = 1
|
80
|
-
album.composite_artist
|
81
|
-
MODEL_DB.sqls.should == ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al')) LIMIT 1"]
|
82
|
-
|
83
|
-
album.name = 'Al2'
|
84
|
-
album.composite_artist
|
85
|
-
MODEL_DB.sqls.should == ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al2')) LIMIT 1"]
|
86
|
-
end
|
87
|
-
|
88
|
-
specify "should work with subclasses" do
|
89
|
-
salbum = Class.new(@Album)
|
90
|
-
oartist = Class.new(@c).set_dataset(:oartist)
|
91
|
-
oartist.columns :id, :name
|
92
|
-
salbum.many_to_one :artist2, :class=>oartist, :key=>:artist_id
|
93
|
-
album = salbum.load(:id => 1, :name=>'Al', :artist_id=>2)
|
94
|
-
album.artist
|
95
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
|
96
|
-
|
97
|
-
album.artist_id = 1
|
98
|
-
album.artist
|
99
|
-
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
@@ -1,337 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
-
|
3
|
-
describe "Sequel::Plugins::IdentityMap" do
|
4
|
-
before do
|
5
|
-
class ::IdentityMapModel < Sequel::Model
|
6
|
-
plugin :identity_map
|
7
|
-
attr_accessor :foo
|
8
|
-
dataset._fetch = proc do |sql|
|
9
|
-
sql =~ /WHERE \(?(\w+\.)?(\w+) = (\d)\)?/
|
10
|
-
{$2.to_sym=>$3.to_i}
|
11
|
-
end
|
12
|
-
def self.waw_identity_map(&block) # with and without
|
13
|
-
with_identity_map(&block)
|
14
|
-
db.reset
|
15
|
-
yield
|
16
|
-
end
|
17
|
-
end
|
18
|
-
class ::IdentityMapAlbum < ::IdentityMapModel
|
19
|
-
columns :artist_id
|
20
|
-
end
|
21
|
-
class ::IdentityMapArtist < ::IdentityMapModel
|
22
|
-
end
|
23
|
-
@c = ::IdentityMapModel
|
24
|
-
@c1 = ::IdentityMapAlbum
|
25
|
-
@c2 = ::IdentityMapArtist
|
26
|
-
MODEL_DB.reset
|
27
|
-
end
|
28
|
-
after do
|
29
|
-
Object.send(:remove_const, :IdentityMapAlbum)
|
30
|
-
Object.send(:remove_const, :IdentityMapArtist)
|
31
|
-
Object.send(:remove_const, :IdentityMapModel)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "#identity_map should return a hash if an identity map is currently being used" do
|
35
|
-
@c.with_identity_map{@c.identity_map.should == {}}
|
36
|
-
end
|
37
|
-
|
38
|
-
it "#identity_map should return nil if an identity map is not currently being used" do
|
39
|
-
@c.identity_map.should == nil
|
40
|
-
end
|
41
|
-
|
42
|
-
it "#identity_map_key should be the same for the same class and pk" do
|
43
|
-
@c.identity_map_key(1).should == @c.identity_map_key(1)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "#identity_map_key should be different for a different class" do
|
47
|
-
@c1.identity_map_key(1).should_not == @c2.identity_map_key(1)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "#identity_map_key should be different for different anonymous classes" do
|
51
|
-
Class.new(@c).identity_map_key(1).should_not == Class.new(@c).identity_map_key(1)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "#identity_map_key should be different for a different pk" do
|
55
|
-
@c.identity_map_key(1).should_not == @c.identity_map_key(2)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "#identity_map_key should be nil for an empty pk values" do
|
59
|
-
@c.identity_map_key(nil).should == nil
|
60
|
-
@c.identity_map_key([]).should == nil
|
61
|
-
@c.identity_map_key([nil]).should == nil
|
62
|
-
end
|
63
|
-
|
64
|
-
it "#load should work even if model doesn't have a primary key" do
|
65
|
-
c = Class.new(@c)
|
66
|
-
c.no_primary_key
|
67
|
-
proc{c.with_identity_map{c.load({})}}.should_not raise_error
|
68
|
-
c.with_identity_map{c.load({}).should_not equal(c.load({}))}
|
69
|
-
end
|
70
|
-
|
71
|
-
it "#load should return an object if there is no current identity map" do
|
72
|
-
o = @c.load(:id=>1)
|
73
|
-
o.should be_a_kind_of(@c)
|
74
|
-
o.values.should == {:id=>1}
|
75
|
-
end
|
76
|
-
|
77
|
-
it "#load should return an object if there is a current identity map" do
|
78
|
-
@c.with_identity_map do
|
79
|
-
o = @c.load(:id=>1)
|
80
|
-
o.should be_a_kind_of(@c)
|
81
|
-
o.values.should == {:id=>1}
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
it "#load should store the object in the current identity map if it isn't already there" do
|
86
|
-
@c.with_identity_map do
|
87
|
-
@c.identity_map[@c.identity_map_key(1)].should == nil
|
88
|
-
o = @c.load(:id=>1)
|
89
|
-
@c.identity_map[@c.identity_map_key(1)].should == o
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
it "#load should update the record in the current identity map if new fields if it is already there" do
|
94
|
-
@c.with_identity_map do
|
95
|
-
o = @c.load(:id=>1, :a=>2)
|
96
|
-
o.values.should == {:id=>1, :a=>2}
|
97
|
-
o = @c.load(:id=>1, :b=>3)
|
98
|
-
o.values.should == {:id=>1, :a=>2, :b=>3}
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
it "#load should not update existing fields in the record if the record is in the current identity map" do
|
103
|
-
@c.with_identity_map do
|
104
|
-
o = @c.load(:id=>1, :a=>2)
|
105
|
-
o.values.should == {:id=>1, :a=>2}
|
106
|
-
o = @c.load(:id=>1, :a=>4)
|
107
|
-
o.values.should == {:id=>1, :a=>2}
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should use the identity map as a lookup cache in Model.[] to save on database queries" do
|
112
|
-
@c.with_identity_map do
|
113
|
-
MODEL_DB.sqls.length.should == 0
|
114
|
-
o = @c[1]
|
115
|
-
MODEL_DB.sqls.length.should == 1
|
116
|
-
o.foo = 1
|
117
|
-
@c[1].foo.should == o.foo
|
118
|
-
MODEL_DB.sqls.length.should == 0
|
119
|
-
@c[2].foo.should_not == o.foo
|
120
|
-
MODEL_DB.sqls.length.should == 1
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
it "should remove instances from the identity map if they are deleted or destroyed" do
|
125
|
-
@c.with_identity_map do
|
126
|
-
MODEL_DB.sqls.length.should == 0
|
127
|
-
o = @c[1]
|
128
|
-
MODEL_DB.sqls.length.should == 1
|
129
|
-
o.foo = 1
|
130
|
-
@c[1].should == o
|
131
|
-
MODEL_DB.sqls.length.should == 0
|
132
|
-
o.destroy
|
133
|
-
MODEL_DB.sqls.length.should == 1
|
134
|
-
@c[1].foo.should_not == o.foo
|
135
|
-
MODEL_DB.sqls.length.should == 1
|
136
|
-
|
137
|
-
MODEL_DB.reset
|
138
|
-
o = @c[2]
|
139
|
-
MODEL_DB.sqls.length.should == 1
|
140
|
-
o.foo = 1
|
141
|
-
@c[2].should == o
|
142
|
-
MODEL_DB.sqls.length.should == 0
|
143
|
-
o.delete
|
144
|
-
MODEL_DB.sqls.length.should == 1
|
145
|
-
@c[2].foo.should_not == o.foo
|
146
|
-
MODEL_DB.sqls.length.should == 1
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
it "should use the identity map as a lookup cache when retrieving many_to_one associated records via a composite key" do
|
151
|
-
@c1.columns :another_id
|
152
|
-
@c1.many_to_one :artist, :class=>@c2, :key=>[:id, :another_id]
|
153
|
-
@c.with_identity_map do
|
154
|
-
MODEL_DB.sqls.length.should == 0
|
155
|
-
o = @c1.load(:id=>1, :another_id=>1, :artist_id=>2)
|
156
|
-
a = o.artist
|
157
|
-
a.should be_a_kind_of(@c2)
|
158
|
-
MODEL_DB.sqls.length.should == 1
|
159
|
-
o = @c1.load(:id=>1, :another_id=>2, :artist_id=>2)
|
160
|
-
o.artist.should == a
|
161
|
-
MODEL_DB.sqls.length.should == 0
|
162
|
-
o = @c1.load(:id=>3, :another_id=>3, :artist_id=>3)
|
163
|
-
o.artist.should_not == a
|
164
|
-
MODEL_DB.sqls.length.should == 1
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
it "should use the identity map as a lookup cache when retrieving many_to_one associated records" do
|
169
|
-
@c1.many_to_one :artist, :class=>@c2
|
170
|
-
@c.with_identity_map do
|
171
|
-
MODEL_DB.sqls.length.should == 0
|
172
|
-
o = @c1.load(:id=>1, :artist_id=>2)
|
173
|
-
a = o.artist
|
174
|
-
a.should be_a_kind_of(@c2)
|
175
|
-
MODEL_DB.sqls.length.should == 1
|
176
|
-
o = @c1.load(:id=>2, :artist_id=>2)
|
177
|
-
o.artist.should == a
|
178
|
-
MODEL_DB.sqls.length.should == 0
|
179
|
-
o = @c1.load(:id=>3, :artist_id=>3)
|
180
|
-
o.artist.should_not == a
|
181
|
-
MODEL_DB.sqls.length.should == 1
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
it "should not use the identity map as a lookup cache for a one_to_one association" do
|
186
|
-
@c2.one_to_one :artist, :class=>@c1, :key=>:artist_id
|
187
|
-
@c.with_identity_map do
|
188
|
-
MODEL_DB.sqls.length.should == 0
|
189
|
-
o = @c2.load(:id=>2)
|
190
|
-
a = o.artist
|
191
|
-
a.should be_a_kind_of(@c1)
|
192
|
-
MODEL_DB.sqls.length.should == 1
|
193
|
-
o.reload
|
194
|
-
MODEL_DB.sqls.length.should == 1
|
195
|
-
o.artist.should == a
|
196
|
-
MODEL_DB.sqls.length.should == 1
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
it "should not use the identity map as a lookup cache if the assocation has a nil :key option" do
|
201
|
-
c = @c2
|
202
|
-
@c1.many_to_one :artist, :class=>@c2, :key=>nil, :dataset=>proc{c.filter(:artist_id=>artist_id)}
|
203
|
-
@c.with_identity_map do
|
204
|
-
MODEL_DB.sqls.length.should == 0
|
205
|
-
o = @c1.load(:id=>1, :artist_id=>2)
|
206
|
-
a = o.artist
|
207
|
-
a.should be_a_kind_of(@c2)
|
208
|
-
MODEL_DB.sqls.length.should == 1
|
209
|
-
o = @c1.load(:id=>2, :artist_id=>2)
|
210
|
-
o.artist.should == a
|
211
|
-
MODEL_DB.sqls.length.should == 1
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
it "should not use the identity map as a lookup cache if the assocation's :primary_key option doesn't match the primary key of the associated class" do
|
216
|
-
@c1.many_to_one :artist, :class=>@c2, :primary_key=>:artist_id
|
217
|
-
@c.with_identity_map do
|
218
|
-
MODEL_DB.sqls.length.should == 0
|
219
|
-
o = @c1.load(:id=>1, :artist_id=>2)
|
220
|
-
a = o.artist
|
221
|
-
a.should be_a_kind_of(@c2)
|
222
|
-
MODEL_DB.sqls.length.should == 1
|
223
|
-
o = @c1.load(:id=>2, :artist_id=>2)
|
224
|
-
o.artist.should == a
|
225
|
-
MODEL_DB.sqls.length.should == 1
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
it "should not use the identity map as a lookup cache if a dynamic callback is used" do
|
230
|
-
@c1.many_to_one :artist, :class=>@c2
|
231
|
-
@c.with_identity_map do
|
232
|
-
MODEL_DB.sqls.length.should == 0
|
233
|
-
o = @c1.load(:id=>1, :artist_id=>2)
|
234
|
-
a = o.artist
|
235
|
-
a.should be_a_kind_of(@c2)
|
236
|
-
MODEL_DB.sqls.length.should == 1
|
237
|
-
o = @c1.load(:id=>2, :artist_id=>2)
|
238
|
-
o.artist.should == a
|
239
|
-
MODEL_DB.sqls.length.should == 0
|
240
|
-
o = @c1.load(:id=>3, :artist_id=>3)
|
241
|
-
o.artist.should_not == a
|
242
|
-
MODEL_DB.sqls.length.should == 1
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
it "should not override custom :eager_loaders for many_to_many associations" do
|
247
|
-
@c1.columns :id
|
248
|
-
@c2.columns :id
|
249
|
-
c = @c2
|
250
|
-
@c1.many_to_many :artists, :class=>@c2, :left_key=>:album_id, :right_key=>:artist_id, :join_table=>:aa, :eager_loader=>(proc do |eo|
|
251
|
-
eo[:rows].each{|object| object.associations[:artists] = [c.load(:id=>object.id)]}
|
252
|
-
end)
|
253
|
-
@c1.dataset._fetch = [{:id=>1}, {:id=>2}, {:id=>3}]
|
254
|
-
|
255
|
-
@c.waw_identity_map do
|
256
|
-
MODEL_DB.sqls.length.should == 0
|
257
|
-
a = @c1.eager(:artists).all
|
258
|
-
MODEL_DB.sqls.length.should == 1
|
259
|
-
a.should == [@c1.load(:id=>1), @c1.load(:id=>2), @c1.load(:id=>3)]
|
260
|
-
a.map{|x| x.artists}.should == [[@c2.load(:id=>1)], [@c2.load(:id=>2)], [@c2.load(:id=>3)]]
|
261
|
-
MODEL_DB.sqls.length.should == 0
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
it "should work correctly when eagerly loading many_to_many associations" do
|
266
|
-
@c1.columns :id
|
267
|
-
@c2.columns :id
|
268
|
-
@c1.many_to_many :artists, :class=>@c2, :left_key=>:album_id, :right_key=>:artist_id, :join_table=>:aa
|
269
|
-
@c1.dataset._fetch = [{:id=>1}, {:id=>2}, {:id=>3}]
|
270
|
-
@c2.dataset._fetch = [{:id=>1, :x_foreign_key_x=>1}, {:id=>1, :x_foreign_key_x=>2}, {:id=>2, :x_foreign_key_x=>1}, {:id=>2, :x_foreign_key_x=>2}, {:id=>3, :x_foreign_key_x=>1}, {:id=>3, :x_foreign_key_x=>1}]
|
271
|
-
|
272
|
-
@c.waw_identity_map do
|
273
|
-
MODEL_DB.sqls.length.should == 0
|
274
|
-
a = @c1.eager(:artists).all
|
275
|
-
MODEL_DB.sqls.length.should == 2
|
276
|
-
a.should == [@c1.load(:id=>1), @c1.load(:id=>2), @c1.load(:id=>3)]
|
277
|
-
a.map{|x| x.artists}.should == [[@c2.load(:id=>1), @c2.load(:id=>2), @c2.load(:id=>3), @c2.load(:id=>3)], [@c2.load(:id=>1), @c2.load(:id=>2)], []]
|
278
|
-
MODEL_DB.sqls.length.should == 0
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
it "should work correctly when eagerly loading many_to_many associations with composite keys" do
|
283
|
-
@c1.columns :id, :id2
|
284
|
-
@c2.columns :id, :id2
|
285
|
-
@c1.set_primary_key [:id, :id2]
|
286
|
-
@c2.set_primary_key [:id, :id2]
|
287
|
-
@c1.many_to_many :artists, :class=>@c2, :left_key=>[:album_id1, :album_id2], :right_key=>[:artist_id1, :artist_id2], :join_table=>:aa
|
288
|
-
@c1.dataset._fetch = [{:id=>1, :id2=>4}, {:id=>2, :id2=>5}, {:id=>3, :id2=>6}]
|
289
|
-
@c2.dataset._fetch = [ {:id=>1, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>1, :x_foreign_key_0_x=>2, :x_foreign_key_1_x=>5}, {:id=>2, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>2, :x_foreign_key_0_x=>2, :x_foreign_key_1_x=>5}, {:id=>3, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>3, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}]
|
290
|
-
|
291
|
-
@c.waw_identity_map do
|
292
|
-
MODEL_DB.sqls.length.should == 0
|
293
|
-
a = @c1.eager(:artists).all
|
294
|
-
MODEL_DB.sqls.length.should == 2
|
295
|
-
a.should == [@c1.load(:id=>1, :id2=>4), @c1.load(:id=>2, :id2=>5), @c1.load(:id=>3, :id2=>6)]
|
296
|
-
a.map{|x| x.artists}.should == [[@c2.load(:id=>1), @c2.load(:id=>2), @c2.load(:id=>3), @c2.load(:id=>3)], [@c2.load(:id=>1), @c2.load(:id=>2)], []]
|
297
|
-
MODEL_DB.sqls.length.should == 0
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
it "should work correctly when eagerly loading many_through_many associations" do
|
302
|
-
@c1.columns :id
|
303
|
-
@c2.columns :id
|
304
|
-
@c1.plugin :many_through_many
|
305
|
-
@c1.many_through_many :artists, [[:aa, :album_id, :artist_id]], :class=>@c2
|
306
|
-
@c1.dataset._fetch = [{:id=>1}, {:id=>2}, {:id=>3}]
|
307
|
-
@c2.dataset._fetch = [{:id=>1, :x_foreign_key_x=>1}, {:id=>1, :x_foreign_key_x=>2}, {:id=>2, :x_foreign_key_x=>1}, {:id=>2, :x_foreign_key_x=>2}, {:id=>3, :x_foreign_key_x=>1}, {:id=>3, :x_foreign_key_x=>1}]
|
308
|
-
|
309
|
-
@c.waw_identity_map do
|
310
|
-
MODEL_DB.sqls.length.should == 0
|
311
|
-
a = @c1.eager(:artists).all
|
312
|
-
MODEL_DB.sqls.length.should == 2
|
313
|
-
a.should == [@c1.load(:id=>1), @c1.load(:id=>2), @c1.load(:id=>3)]
|
314
|
-
a.map{|x| x.artists}.should == [[@c2.load(:id=>1), @c2.load(:id=>2), @c2.load(:id=>3), @c2.load(:id=>3)], [@c2.load(:id=>1), @c2.load(:id=>2)], []]
|
315
|
-
MODEL_DB.sqls.length.should == 0
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
it "should work correctly when eagerly loading many_to_many associations with composite keys" do
|
320
|
-
@c1.columns :id, :id2
|
321
|
-
@c2.columns :id
|
322
|
-
@c1.set_primary_key [:id, :id2]
|
323
|
-
@c1.plugin :many_through_many
|
324
|
-
@c1.many_through_many :artists, [[:aa, [:album_id1, :album_id2], :artist_id]], :class=>@c2
|
325
|
-
@c1.dataset._fetch = [{:id=>1, :id2=>4}, {:id=>2, :id2=>5}, {:id=>3, :id2=>6}]
|
326
|
-
@c2.dataset._fetch = [ {:id=>1, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>1, :x_foreign_key_0_x=>2, :x_foreign_key_1_x=>5}, {:id=>2, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>2, :x_foreign_key_0_x=>2, :x_foreign_key_1_x=>5}, {:id=>3, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}, {:id=>3, :x_foreign_key_0_x=>1, :x_foreign_key_1_x=>4}]
|
327
|
-
|
328
|
-
@c.waw_identity_map do
|
329
|
-
MODEL_DB.sqls.length.should == 0
|
330
|
-
a = @c1.eager(:artists).all
|
331
|
-
MODEL_DB.sqls.length.should == 2
|
332
|
-
a.should == [@c1.load(:id=>1, :id2=>4), @c1.load(:id=>2, :id2=>5), @c1.load(:id=>3, :id2=>6)]
|
333
|
-
a.map{|x| x.artists}.should == [[@c2.load(:id=>1), @c2.load(:id=>2), @c2.load(:id=>3), @c2.load(:id=>3)], [@c2.load(:id=>1), @c2.load(:id=>2)], []]
|
334
|
-
MODEL_DB.sqls.length.should == 0
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|