sequel 3.21.0 → 3.39.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.
- data/CHANGELOG +1061 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +103 -63
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +67 -51
- data/doc/advanced_associations.rdoc +189 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +10 -10
- data/doc/dataset_filtering.rdoc +54 -42
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +89 -557
- data/doc/model_hooks.rdoc +80 -29
- data/doc/object_model.rdoc +547 -0
- data/doc/opening_databases.rdoc +114 -53
- data/doc/prepared_statements.rdoc +41 -15
- data/doc/querying.rdoc +137 -56
- data/doc/reflection.rdoc +36 -10
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/schema_modification.rdoc +585 -0
- data/doc/sharding.rdoc +99 -8
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +169 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +78 -43
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +2 -61
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +56 -0
- data/lib/sequel/adapters/jdbc/derby.rb +325 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +279 -97
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +125 -222
- data/lib/sequel/adapters/mysql2.rb +65 -56
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +368 -138
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +343 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +401 -116
- data/lib/sequel/adapters/shared/mysql.rb +424 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +257 -45
- data/lib/sequel/adapters/shared/postgres.rb +675 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +285 -96
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +10 -12
- data/lib/sequel/adapters/swift/postgres.rb +13 -79
- data/lib/sequel/adapters/swift/sqlite.rb +9 -6
- data/lib/sequel/adapters/swift.rb +28 -19
- data/lib/sequel/adapters/tinytds.rb +174 -22
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
- data/lib/sequel/adapters/utils/pg_types.rb +81 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +43 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +38 -28
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +190 -46
- data/lib/sequel/database/query.rb +272 -110
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +300 -67
- data/lib/sequel/dataset/actions.rb +344 -90
- data/lib/sequel/dataset/features.rb +101 -8
- data/lib/sequel/dataset/graph.rb +42 -15
- data/lib/sequel/dataset/misc.rb +52 -25
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +305 -54
- data/lib/sequel/dataset/sql.rb +720 -292
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +83 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +72 -0
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
- data/lib/sequel/extensions/eval_inspect.rb +173 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +100 -11
- data/lib/sequel/extensions/named_timezones.rb +9 -0
- data/lib/sequel/extensions/null_dataset.rb +94 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +537 -0
- data/lib/sequel/extensions/pg_array_ops.rb +263 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
- data/lib/sequel/extensions/pg_hstore.rb +313 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
- data/lib/sequel/extensions/pg_inet.rb +113 -0
- data/lib/sequel/extensions/pg_interval.rb +191 -0
- data/lib/sequel/extensions/pg_json.rb +208 -0
- data/lib/sequel/extensions/pg_range.rb +512 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +572 -0
- data/lib/sequel/extensions/pg_row_ops.rb +182 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
- data/lib/sequel/extensions/pretty_table.rb +17 -72
- data/lib/sequel/extensions/query.rb +8 -4
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +282 -76
- data/lib/sequel/extensions/select_remove.rb +39 -0
- data/lib/sequel/extensions/server_block.rb +140 -0
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +8 -110
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
- data/lib/sequel/extensions/to_dot.rb +99 -83
- data/lib/sequel/model/associations.rb +1263 -409
- data/lib/sequel/model/base.rb +624 -171
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +24 -2
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +72 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +134 -15
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +58 -6
- data/lib/sequel/plugins/list.rb +13 -2
- data/lib/sequel/plugins/many_through_many.rb +103 -51
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +150 -66
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/prepared_statements.rb +167 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +31 -17
- data/lib/sequel/plugins/schema.rb +8 -3
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +29 -3
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +55 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +649 -122
- data/lib/sequel/timezones.rb +67 -40
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +194 -66
- data/spec/adapters/mysql_spec.rb +475 -306
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +1982 -325
- data/spec/adapters/spec_helper.rb +9 -6
- data/spec/adapters/sqlite_spec.rb +203 -75
- data/spec/core/connection_pool_spec.rb +218 -93
- data/spec/core/database_spec.rb +956 -522
- data/spec/core/dataset_spec.rb +1631 -1242
- data/spec/core/expression_filters_spec.rb +690 -334
- data/spec/core/mock_adapter_spec.rb +453 -0
- data/spec/core/object_graph_spec.rb +88 -129
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +556 -53
- data/spec/core/spec_helper.rb +7 -48
- data/spec/core_extensions_spec.rb +626 -0
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/caching_spec.rb +47 -51
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +88 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/eval_inspect_spec.rb +67 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +97 -128
- data/spec/extensions/identity_map_spec.rb +142 -24
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -12
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +49 -40
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +368 -254
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +268 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +112 -0
- data/spec/extensions/pg_array_spec.rb +320 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
- data/spec/extensions/pg_hstore_spec.rb +194 -0
- data/spec/extensions/pg_inet_spec.rb +47 -0
- data/spec/extensions/pg_interval_spec.rb +72 -0
- data/spec/extensions/pg_json_spec.rb +99 -0
- data/spec/extensions/pg_range_ops_spec.rb +56 -0
- data/spec/extensions/pg_range_spec.rb +395 -0
- data/spec/extensions/pg_row_ops_spec.rb +58 -0
- data/spec/extensions/pg_row_plugin_spec.rb +49 -0
- data/spec/extensions/pg_row_spec.rb +323 -0
- data/spec/extensions/pg_statement_cache_spec.rb +208 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +167 -0
- data/spec/extensions/query_spec.rb +9 -3
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +434 -49
- data/spec/extensions/schema_spec.rb +30 -49
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +86 -48
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +23 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +34 -67
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +8 -11
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +9 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +58 -67
- data/spec/extensions/validation_helpers_spec.rb +31 -37
- data/spec/extensions/xml_serializer_spec.rb +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +11 -5
- data/spec/integration/dataset_test.rb +717 -129
- data/spec/integration/eager_loader_test.rb +38 -54
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +604 -147
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +367 -57
- data/spec/integration/spec_helper.rb +42 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +31 -8
- data/spec/model/association_reflection_spec.rb +207 -8
- data/spec/model/associations_spec.rb +1206 -693
- data/spec/model/base_spec.rb +334 -100
- data/spec/model/dataset_methods_spec.rb +45 -27
- data/spec/model/eager_loading_spec.rb +828 -692
- data/spec/model/hooks_spec.rb +355 -67
- data/spec/model/model_spec.rb +251 -179
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +506 -232
- data/spec/model/spec_helper.rb +16 -77
- data/spec/model/validations_spec.rb +38 -2
- data/spec/rcov.opts +2 -0
- metadata +209 -80
- data/spec/core/core_sql_spec.rb +0 -451
|
@@ -68,6 +68,16 @@ module Sequel
|
|
|
68
68
|
|
|
69
69
|
private
|
|
70
70
|
|
|
71
|
+
# If there are any instance filters, make sure not to use the
|
|
72
|
+
# instance delete optimization.
|
|
73
|
+
def _delete_without_checking
|
|
74
|
+
if @instance_filters && !@instance_filters.empty?
|
|
75
|
+
_delete_dataset.delete
|
|
76
|
+
else
|
|
77
|
+
super
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
71
81
|
# Lazily initialize the instance filter array.
|
|
72
82
|
def instance_filters
|
|
73
83
|
@instance_filters ||= []
|
|
@@ -29,7 +29,7 @@ module Sequel
|
|
|
29
29
|
BEFORE_HOOKS = Sequel::Model::BEFORE_HOOKS
|
|
30
30
|
AFTER_HOOKS = Sequel::Model::AFTER_HOOKS - [:after_initialize]
|
|
31
31
|
HOOKS = BEFORE_HOOKS + AFTER_HOOKS
|
|
32
|
-
HOOKS.each{|h| class_eval("def #{h}_hook(&block); add_instance_hook(:#{h}, &block) end", __FILE__, __LINE__)}
|
|
32
|
+
HOOKS.each{|h| class_eval("def #{h}_hook(&block); add_instance_hook(:#{h}, &block); self end", __FILE__, __LINE__)}
|
|
33
33
|
|
|
34
34
|
BEFORE_HOOKS.each{|h| class_eval("def #{h}; run_before_instance_hooks(:#{h}) == false ? false : super end", __FILE__, __LINE__)}
|
|
35
35
|
AFTER_HOOKS.each{|h| class_eval(<<-END, __FILE__, __LINE__ + 1)}
|
|
@@ -56,6 +56,11 @@ module Sequel
|
|
|
56
56
|
# Album.to_json
|
|
57
57
|
# Album.filter(:artist_id=>1).to_json(:include=>:tags)
|
|
58
58
|
#
|
|
59
|
+
# If you have an existing array of model instances you want to convert to
|
|
60
|
+
# JSON, you can call the class to_json method with the :array option:
|
|
61
|
+
#
|
|
62
|
+
# Album.to_json(:array=>[Album[1], Album[2]])
|
|
63
|
+
#
|
|
59
64
|
# Usage:
|
|
60
65
|
#
|
|
61
66
|
# # Add JSON output capability to all model subclass instances (called before loading subclasses)
|
|
@@ -134,8 +139,13 @@ module Sequel
|
|
|
134
139
|
module InstanceMethods
|
|
135
140
|
# Parse the provided JSON, which should return a hash,
|
|
136
141
|
# and call +set+ with that hash.
|
|
137
|
-
def from_json(json)
|
|
138
|
-
|
|
142
|
+
def from_json(json, opts={})
|
|
143
|
+
h = JSON.parse(json)
|
|
144
|
+
if fields = opts[:fields]
|
|
145
|
+
set_fields(h, fields, opts)
|
|
146
|
+
else
|
|
147
|
+
set(h)
|
|
148
|
+
end
|
|
139
149
|
end
|
|
140
150
|
|
|
141
151
|
# Return a string in JSON format. Accepts the following
|
|
@@ -149,7 +159,7 @@ module Sequel
|
|
|
149
159
|
# to include in the JSON output. Using a nested
|
|
150
160
|
# hash, you can pass options to associations
|
|
151
161
|
# to affect the JSON used for associated objects.
|
|
152
|
-
# :naked :: Not to add the JSON.create_id key to the JSON
|
|
162
|
+
# :naked :: Not to add the JSON.create_id (json_class) key to the JSON
|
|
153
163
|
# output hash, so when the JSON is parsed, it
|
|
154
164
|
# will yield a hash instead of a model object.
|
|
155
165
|
# :only :: Symbol or Array of Symbols of columns to only
|
|
@@ -195,7 +205,21 @@ module Sequel
|
|
|
195
205
|
module DatasetMethods
|
|
196
206
|
# Return a JSON string representing an array of all objects in
|
|
197
207
|
# this dataset. Takes the same options as the the instance
|
|
198
|
-
# method, and passes them to every instance.
|
|
208
|
+
# method, and passes them to every instance. Additionally,
|
|
209
|
+
# respects the following options:
|
|
210
|
+
#
|
|
211
|
+
# :array :: An array of instances. If this is not provided,
|
|
212
|
+
# calls #all on the receiver to get the array.
|
|
213
|
+
# :root :: If set to :collection, only wraps the collection
|
|
214
|
+
# in a root object. If set to :instance, only wraps
|
|
215
|
+
# the instances in a root object. If set to :both,
|
|
216
|
+
# wraps both the collection and instances in a root
|
|
217
|
+
# object. Unfortunately, for backwards compatibility,
|
|
218
|
+
# if this option is true and doesn't match one of those
|
|
219
|
+
# symbols, it defaults to both. That may change in a
|
|
220
|
+
# future version, so for forwards compatibility, you
|
|
221
|
+
# should pick a specific symbol for your desired
|
|
222
|
+
# behavior.
|
|
199
223
|
def to_json(*a)
|
|
200
224
|
if opts = a.first.is_a?(Hash)
|
|
201
225
|
opts = model.json_serializer_opts.merge(a.first)
|
|
@@ -203,8 +227,36 @@ module Sequel
|
|
|
203
227
|
else
|
|
204
228
|
opts = model.json_serializer_opts
|
|
205
229
|
end
|
|
206
|
-
|
|
207
|
-
opts[:root]
|
|
230
|
+
|
|
231
|
+
collection_root = case opts[:root]
|
|
232
|
+
when nil, false, :instance
|
|
233
|
+
false
|
|
234
|
+
when :collection
|
|
235
|
+
opts = opts.dup
|
|
236
|
+
opts.delete(:root)
|
|
237
|
+
opts[:naked] = true unless opts.has_key?(:naked)
|
|
238
|
+
true
|
|
239
|
+
else
|
|
240
|
+
true
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
res = if row_proc
|
|
244
|
+
array = if opts[:array]
|
|
245
|
+
opts = opts.dup
|
|
246
|
+
opts.delete(:array)
|
|
247
|
+
else
|
|
248
|
+
all
|
|
249
|
+
end
|
|
250
|
+
array.map{|obj| Literal.new(obj.to_json(opts))}
|
|
251
|
+
else
|
|
252
|
+
all
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
if collection_root
|
|
256
|
+
{model.send(:pluralize, model.send(:underscore, model.to_s)) => res}.to_json(*a)
|
|
257
|
+
else
|
|
258
|
+
res.to_json(*a)
|
|
259
|
+
end
|
|
208
260
|
end
|
|
209
261
|
end
|
|
210
262
|
end
|
data/lib/sequel/plugins/list.rb
CHANGED
|
@@ -39,9 +39,11 @@ module Sequel
|
|
|
39
39
|
# Item.plugin :list, :scope=>:user_id
|
|
40
40
|
#
|
|
41
41
|
# Note that using this plugin modifies the order of the model's dataset to
|
|
42
|
-
# sort by the position and scope fields.
|
|
42
|
+
# sort by the position and scope fields. Also note that this plugin is subject to
|
|
43
|
+
# race conditions, and is not safe when concurrent modifications are made
|
|
44
|
+
# to the same list.
|
|
43
45
|
#
|
|
44
|
-
#
|
|
46
|
+
# Additionally, note that unlike ruby arrays, the list plugin assumes that the
|
|
45
47
|
# first entry in the list has position 1, not position 0.
|
|
46
48
|
#
|
|
47
49
|
# Copyright (c) 2007-2010 Sharon Rosner, Wayne E. Seguin, Aman Gupta, Adrian Madrid, Jeremy Evans
|
|
@@ -90,6 +92,15 @@ module Sequel
|
|
|
90
92
|
list_dataset.first(position_field => p)
|
|
91
93
|
end
|
|
92
94
|
|
|
95
|
+
# Set the value of the position_field to the maximum value plus 1 unless the
|
|
96
|
+
# position field already has a value.
|
|
97
|
+
def before_create
|
|
98
|
+
unless send(position_field)
|
|
99
|
+
send("#{position_field}=", list_dataset.max(position_field).to_i+1)
|
|
100
|
+
end
|
|
101
|
+
super
|
|
102
|
+
end
|
|
103
|
+
|
|
93
104
|
# Find the last position in the list containing this instance.
|
|
94
105
|
def last_position
|
|
95
106
|
list_dataset.max(position_field).to_i
|
|
@@ -47,20 +47,18 @@ module Sequel
|
|
|
47
47
|
class ManyThroughManyAssociationReflection < Sequel::Model::Associations::ManyToManyAssociationReflection
|
|
48
48
|
Sequel::Model::Associations::ASSOCIATION_TYPES[:many_through_many] = self
|
|
49
49
|
|
|
50
|
-
# The table containing the column to use for the associated key when eagerly loading
|
|
51
|
-
def associated_key_table
|
|
52
|
-
self[:associated_key_table] = self[:final_reverse_edge][:alias]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
50
|
# The default associated key alias(es) to use when eager loading
|
|
56
51
|
# associations via eager.
|
|
57
52
|
def default_associated_key_alias
|
|
58
53
|
self[:uses_left_composite_keys] ? (0...self[:through].first[:left].length).map{|i| :"x_foreign_key_#{i}_x"} : :x_foreign_key_x
|
|
59
54
|
end
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
%w'associated_key_table predicate_key edges final_edge final_reverse_edge reverse_edges'.each do |meth|
|
|
57
|
+
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
58
|
+
def #{meth}
|
|
59
|
+
cached_fetch(:#{meth}){calculate_edges[:#{meth}]}
|
|
60
|
+
end
|
|
61
|
+
END
|
|
64
62
|
end
|
|
65
63
|
|
|
66
64
|
# Many through many associations don't have a reciprocal
|
|
@@ -68,11 +66,6 @@ module Sequel
|
|
|
68
66
|
nil
|
|
69
67
|
end
|
|
70
68
|
|
|
71
|
-
# The list of joins to use when lazy loading or eager loading
|
|
72
|
-
def reverse_edges
|
|
73
|
-
self[:reverse_edges] || calculate_edges || self[:reverse_edges]
|
|
74
|
-
end
|
|
75
|
-
|
|
76
69
|
private
|
|
77
70
|
|
|
78
71
|
# Make sure to use unique table aliases when lazy loading or eager loading
|
|
@@ -94,7 +87,7 @@ module Sequel
|
|
|
94
87
|
|
|
95
88
|
# Transform the :through option into a list of edges and reverse edges to use to join tables when loading the association.
|
|
96
89
|
def calculate_edges
|
|
97
|
-
es = [{:left_table=>self[:model].table_name, :left_key=>self[:
|
|
90
|
+
es = [{:left_table=>self[:model].table_name, :left_key=>self[:left_primary_key_column]}]
|
|
98
91
|
self[:through].each do |t|
|
|
99
92
|
es.last.merge!(:right_key=>t[:left], :right_table=>t[:table], :join_type=>t[:join_type]||self[:graph_join_type], :conditions=>(t[:conditions]||[]).to_a, :block=>t[:block])
|
|
100
93
|
es.last[:only_conditions] = t[:only_conditions] if t.include?(:only_conditions)
|
|
@@ -109,37 +102,38 @@ module Sequel
|
|
|
109
102
|
reverse_edges = es.reverse.map{|e| {:table=>e[:left_table], :left=>e[:left_key], :right=>e[:right_key]}}
|
|
110
103
|
reverse_edges.pop
|
|
111
104
|
calculate_reverse_edge_aliases(reverse_edges)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
105
|
+
final_reverse_edge = reverse_edges.pop
|
|
106
|
+
final_reverse_alias = final_reverse_edge[:alias]
|
|
107
|
+
|
|
108
|
+
h = {:final_edge=>edges.pop,
|
|
109
|
+
:final_reverse_edge=>final_reverse_edge,
|
|
110
|
+
:edges=>edges,
|
|
111
|
+
:reverse_edges=>reverse_edges,
|
|
112
|
+
:predicate_key=>qualify(final_reverse_alias, edges.first[:right]),
|
|
113
|
+
:associated_key_table=>final_reverse_edge[:alias],
|
|
114
|
+
}
|
|
115
|
+
h.each{|k, v| cached_set(k, v)}
|
|
116
|
+
h
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
|
+
|
|
119
120
|
module ClassMethods
|
|
120
121
|
# Create a many_through_many association. Arguments:
|
|
121
122
|
# * name - Same as associate, the name of the association.
|
|
122
123
|
# * through - The tables and keys to join between the current table and the associated table.
|
|
123
124
|
# Must be an array, with elements that are either 3 element arrays, or hashes with keys :table, :left, and :right.
|
|
124
125
|
# The required entries in the array/hash are:
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
126
|
+
# :table (first array element) :: The name of the table to join.
|
|
127
|
+
# :left (middle array element) :: The key joining the table to the previous table. Can use an
|
|
128
|
+
# array of symbols for a composite key association.
|
|
129
|
+
# :right (last array element) :: The key joining the table to the next table. Can use an
|
|
130
|
+
# array of symbols for a composite key association.
|
|
130
131
|
# If a hash is provided, the following keys are respected when using eager_graph:
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
# * opts - The options for the associaion. Takes the same options as
|
|
136
|
-
# * :left_primary_key - column in current table that the first :left option in
|
|
137
|
-
# through points to, as a symbol. Defaults to primary key of current table. Can use an
|
|
138
|
-
# array of symbols for a composite key association.
|
|
139
|
-
# * :right_primary_key - column in associated table that the final :right option in
|
|
140
|
-
# through points to, as a symbol. Defaults to primary key of the associated table. Can use an
|
|
141
|
-
# array of symbols for a composite key association.
|
|
142
|
-
# * :uniq - Adds a after_load callback that makes the array of objects unique.
|
|
132
|
+
# :block :: A proc to use as the block argument to join.
|
|
133
|
+
# :conditions :: Extra conditions to add to the JOIN ON clause. Must be a hash or array of two pairs.
|
|
134
|
+
# :join_type :: The join type to use for the join, defaults to :left_outer.
|
|
135
|
+
# :only_conditions :: Conditions to use for the join instead of the ones specified by the keys.
|
|
136
|
+
# * opts - The options for the associaion. Takes the same options as many_to_many.
|
|
143
137
|
def many_through_many(name, through, opts={}, &block)
|
|
144
138
|
associate(:many_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
|
|
145
139
|
end
|
|
@@ -170,24 +164,41 @@ module Sequel
|
|
|
170
164
|
uses_lcks = opts[:uses_left_composite_keys] = left_key.is_a?(Array)
|
|
171
165
|
left_keys = Array(left_key)
|
|
172
166
|
left_pk = (opts[:left_primary_key] ||= self.primary_key)
|
|
167
|
+
opts[:eager_loader_key] = left_pk unless opts.has_key?(:eager_loader_key)
|
|
173
168
|
left_pks = opts[:left_primary_keys] = Array(left_pk)
|
|
169
|
+
lpkc = opts[:left_primary_key_column] ||= left_pk
|
|
170
|
+
lpkcs = opts[:left_primary_key_columns] ||= Array(lpkc)
|
|
174
171
|
opts[:dataset] ||= lambda do
|
|
175
172
|
ds = opts.associated_class
|
|
176
|
-
opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
|
|
177
|
-
ft = opts
|
|
178
|
-
ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) +
|
|
173
|
+
opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias], :qualify=>:deep)}
|
|
174
|
+
ft = opts.final_reverse_edge
|
|
175
|
+
ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + opts.predicate_keys.zip(left_pks.map{|k| send(k)}), :table_alias=>ft[:alias], :qualify=>:deep)
|
|
179
176
|
end
|
|
180
177
|
|
|
181
178
|
left_key_alias = opts[:left_key_alias] ||= opts.default_associated_key_alias
|
|
182
179
|
opts[:eager_loader] ||= lambda do |eo|
|
|
183
|
-
h = eo[:
|
|
184
|
-
|
|
180
|
+
h = eo[:id_map]
|
|
181
|
+
rows = eo[:rows]
|
|
182
|
+
rows.each{|object| object.associations[name] = []}
|
|
185
183
|
ds = opts.associated_class
|
|
186
|
-
opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
|
|
187
|
-
ft = opts
|
|
188
|
-
|
|
189
|
-
ds =
|
|
190
|
-
|
|
184
|
+
opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias], :qualify=>:deep)}
|
|
185
|
+
ft = opts.final_reverse_edge
|
|
186
|
+
ds = ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + [[opts.predicate_key, h.keys]], :table_alias=>ft[:alias], :qualify=>:deep)
|
|
187
|
+
ds = model.eager_loading_dataset(opts, ds, nil, eo[:associations], eo)
|
|
188
|
+
case opts.eager_limit_strategy
|
|
189
|
+
when :window_function
|
|
190
|
+
delete_rn = true
|
|
191
|
+
rn = ds.row_number_column
|
|
192
|
+
ds = apply_window_function_eager_limit_strategy(ds, opts)
|
|
193
|
+
when :correlated_subquery
|
|
194
|
+
ds = apply_correlated_subquery_eager_limit_strategy(ds, opts) do |xds|
|
|
195
|
+
dsa = ds.send(:dataset_alias, 2)
|
|
196
|
+
opts.reverse_edges.each{|t| xds = xds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
|
|
197
|
+
xds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + left_keys.map{|k| [k, SQL::QualifiedIdentifier.new(ft[:table], k)]}, :table_alias=>dsa, :qualify=>:deep)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
ds.all do |assoc_record|
|
|
201
|
+
assoc_record.values.delete(rn) if delete_rn
|
|
191
202
|
hash_key = if uses_lcks
|
|
192
203
|
left_key_alias.map{|k| assoc_record.values.delete(k)}
|
|
193
204
|
else
|
|
@@ -196,6 +207,10 @@ module Sequel
|
|
|
196
207
|
next unless objects = h[hash_key]
|
|
197
208
|
objects.each{|object| object.associations[name].push(assoc_record)}
|
|
198
209
|
end
|
|
210
|
+
if opts.eager_limit_strategy == :ruby
|
|
211
|
+
limit, offset = opts.limit_and_offset
|
|
212
|
+
rows.each{|o| o.associations[name] = o.associations[name].slice(offset||0, limit) || []}
|
|
213
|
+
end
|
|
199
214
|
end
|
|
200
215
|
|
|
201
216
|
join_type = opts[:graph_join_type]
|
|
@@ -204,19 +219,56 @@ module Sequel
|
|
|
204
219
|
only_conditions = opts[:graph_only_conditions]
|
|
205
220
|
use_only_conditions = opts.include?(:graph_only_conditions)
|
|
206
221
|
conditions = opts[:graph_conditions]
|
|
207
|
-
opts[:eager_grapher] ||= proc do |
|
|
208
|
-
|
|
222
|
+
opts[:eager_grapher] ||= proc do |eo|
|
|
223
|
+
ds = eo[:self]
|
|
224
|
+
iq = eo[:implicit_qualifier]
|
|
209
225
|
opts.edges.each do |t|
|
|
210
|
-
ds = ds.graph(t[:table], t.fetch(:only_conditions, (Array(t[:right]).zip(Array(t[:left])) + t[:conditions])), :select=>false, :table_alias=>ds.unused_table_alias(t[:table]), :join_type=>t[:join_type], :implicit_qualifier=>iq, &t[:block])
|
|
226
|
+
ds = ds.graph(t[:table], t.fetch(:only_conditions, (Array(t[:right]).zip(Array(t[:left])) + t[:conditions])), :select=>false, :table_alias=>ds.unused_table_alias(t[:table]), :join_type=>t[:join_type], :qualify=>:deep, :implicit_qualifier=>iq, &t[:block])
|
|
211
227
|
iq = nil
|
|
212
228
|
end
|
|
213
|
-
fe = opts
|
|
214
|
-
ds.graph(opts.associated_class, use_only_conditions ? only_conditions : (Array(opts.right_primary_key).zip(Array(fe[:left])) + conditions), :select=>select, :table_alias=>
|
|
229
|
+
fe = opts.final_edge
|
|
230
|
+
ds.graph(opts.associated_class, use_only_conditions ? only_conditions : (Array(opts.right_primary_key).zip(Array(fe[:left])) + conditions), :select=>select, :table_alias=>eo[:table_alias], :qualify=>:deep, :join_type=>join_type, &graph_block)
|
|
215
231
|
end
|
|
216
232
|
|
|
217
233
|
def_association_dataset_methods(opts)
|
|
218
234
|
end
|
|
219
235
|
end
|
|
236
|
+
|
|
237
|
+
module DatasetMethods
|
|
238
|
+
private
|
|
239
|
+
|
|
240
|
+
# Use a subquery to filter rows to those related to the given associated object
|
|
241
|
+
def many_through_many_association_filter_expression(op, ref, obj)
|
|
242
|
+
lpks = ref[:left_primary_key_columns]
|
|
243
|
+
lpks = lpks.first if lpks.length == 1
|
|
244
|
+
lpks = ref.qualify(model.table_name, lpks)
|
|
245
|
+
edges = ref.edges
|
|
246
|
+
first, rest = edges.first, edges[1..-1]
|
|
247
|
+
last = edges.last
|
|
248
|
+
ds = model.db[first[:table]].select(*Array(ref.qualify(first[:table], first[:right])))
|
|
249
|
+
rest.each{|e| ds = ds.join(e[:table], e.fetch(:only_conditions, (Array(e[:right]).zip(Array(e[:left])) + e[:conditions])), :table_alias=>ds.unused_table_alias(e[:table]), :qualify=>:deep, &e[:block])}
|
|
250
|
+
last_alias = if rest.empty?
|
|
251
|
+
first[:table]
|
|
252
|
+
else
|
|
253
|
+
last_join = ds.opts[:join].last
|
|
254
|
+
last_join.table_alias || last_join.table
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
meths = if obj.is_a?(Sequel::Dataset)
|
|
258
|
+
ref.qualify(obj.model.table_name, ref.right_primary_keys)
|
|
259
|
+
else
|
|
260
|
+
ref.right_primary_key_methods
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
exp = association_filter_key_expression(ref.qualify(last_alias, Array(ref.final_edge[:left])), meths, obj)
|
|
264
|
+
if exp == SQL::Constants::FALSE
|
|
265
|
+
association_filter_handle_inversion(op, exp, Array(lpks))
|
|
266
|
+
else
|
|
267
|
+
ds = ds.where(exp).exclude(SQL::BooleanExpression.from_value_pairs(ds.opts[:select].zip([]), :OR))
|
|
268
|
+
association_filter_handle_inversion(op, SQL::BooleanExpression.from_value_pairs(lpks=>ds), Array(lpks))
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
220
272
|
end
|
|
221
273
|
end
|
|
222
274
|
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
module Plugins
|
|
3
|
+
# This is a fairly simple plugin that modifies the internal association loading logic
|
|
4
|
+
# for many_to_one associations to use a simple primary key lookup on the associated
|
|
5
|
+
# class, which is generally faster as it uses mostly static SQL. Additional, if the
|
|
6
|
+
# associated class is caching primary key lookups, you get the benefit of a cached
|
|
7
|
+
# lookup.
|
|
8
|
+
#
|
|
9
|
+
# This plugin is generally not as fast as the prepared_statements_associations plugin
|
|
10
|
+
# in the case where the model is not caching primary key lookups, however, it is
|
|
11
|
+
# probably significantly faster if the model is caching primary key lookups. If
|
|
12
|
+
# the prepared_statements_associations plugin has been loaded first, this
|
|
13
|
+
# plugin will only use the primary key lookup code if the associated model is
|
|
14
|
+
# caching primary key lookups.
|
|
15
|
+
#
|
|
16
|
+
# This plugin attempts to determine cases where the primary key lookup would have
|
|
17
|
+
# different results than the regular lookup, and use the regular lookup in that case,
|
|
18
|
+
# but it cannot handle all situations correctly, which is why it is not Sequel's
|
|
19
|
+
# default behavior.
|
|
20
|
+
#
|
|
21
|
+
# You can disable primary key lookups on a per association basis with this
|
|
22
|
+
# plugin using the :many_to_one_pk_lookup=>false association option.
|
|
23
|
+
#
|
|
24
|
+
# Usage:
|
|
25
|
+
#
|
|
26
|
+
# # Make all model subclass instances use primary key lookups for many_to_one
|
|
27
|
+
# # association loading
|
|
28
|
+
# Sequel::Model.plugin :many_to_one_pk_lookup
|
|
29
|
+
#
|
|
30
|
+
# # Do so for just the album class.
|
|
31
|
+
# Album.plugin :many_to_one_pk_lookup
|
|
32
|
+
module ManyToOnePkLookup
|
|
33
|
+
module InstanceMethods
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# If the current association is a fairly simple many_to_one association, use
|
|
37
|
+
# a simple primary key lookup on the associated model, which can benefit from
|
|
38
|
+
# caching if the associated model is using caching.
|
|
39
|
+
def _load_associated_object(opts, dynamic_opts)
|
|
40
|
+
klass = opts.associated_class
|
|
41
|
+
cache_lookup = opts.send(:cached_fetch, :many_to_one_pk_lookup) do
|
|
42
|
+
opts[:type] == :many_to_one &&
|
|
43
|
+
opts[:key] &&
|
|
44
|
+
opts.primary_key == klass.primary_key
|
|
45
|
+
end
|
|
46
|
+
if cache_lookup &&
|
|
47
|
+
!dynamic_opts[:callback] &&
|
|
48
|
+
(o = klass.send(:primary_key_lookup, ((fk = opts[:key]).is_a?(Array) ? fk.map{|c| send(c)} : send(fk))))
|
|
49
|
+
o
|
|
50
|
+
else
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Deal with the situation where the prepared_statements_associations plugin is
|
|
56
|
+
# loaded first, by using a primary key lookup for many_to_one associations if
|
|
57
|
+
# the associated class is using caching, and using the default code otherwise.
|
|
58
|
+
# This is done because the prepared_statements_associations code is probably faster
|
|
59
|
+
# than the primary key lookup this plugin uses if the model is not caching lookups,
|
|
60
|
+
# but probably slower if the model is caching lookups.
|
|
61
|
+
def _load_associated_objects(opts, dynamic_opts={})
|
|
62
|
+
if opts.can_have_associated_objects?(self) && opts[:type] == :many_to_one && opts.associated_class.respond_to?(:cache_get_pk)
|
|
63
|
+
_load_associated_object(opts, dynamic_opts)
|
|
64
|
+
else
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|