sequel 3.21.0 → 3.41.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 +1131 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +106 -65
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +68 -52
- data/doc/advanced_associations.rdoc +201 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/bin_sequel.rdoc +144 -0
- 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 +576 -0
- data/doc/opening_databases.rdoc +121 -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/release_notes/3.40.0.txt +73 -0
- data/doc/release_notes/3.41.0.txt +155 -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/access.rb +334 -0
- data/lib/sequel/adapters/ado/mssql.rb +18 -12
- data/lib/sequel/adapters/ado.rb +69 -21
- data/lib/sequel/adapters/amalgalite.rb +17 -14
- data/lib/sequel/adapters/cubrid.rb +143 -0
- data/lib/sequel/adapters/db2.rb +178 -85
- data/lib/sequel/adapters/dbi.rb +19 -21
- 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 +20 -39
- data/lib/sequel/adapters/firebird.rb +33 -210
- data/lib/sequel/adapters/ibmdb.rb +452 -0
- data/lib/sequel/adapters/informix.rb +6 -29
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
- data/lib/sequel/adapters/jdbc/db2.rb +78 -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 +68 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -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 +16 -28
- 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 +72 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +308 -114
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +130 -230
- data/lib/sequel/adapters/mysql2.rb +64 -63
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +29 -10
- data/lib/sequel/adapters/openbase.rb +7 -11
- data/lib/sequel/adapters/oracle.rb +364 -57
- data/lib/sequel/adapters/postgres.rb +379 -145
- data/lib/sequel/adapters/shared/access.rb +236 -11
- data/lib/sequel/adapters/shared/cubrid.rb +216 -0
- data/lib/sequel/adapters/shared/db2.rb +353 -0
- data/lib/sequel/adapters/shared/firebird.rb +231 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +412 -116
- data/lib/sequel/adapters/shared/mysql.rb +396 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
- data/lib/sequel/adapters/shared/oracle.rb +262 -45
- data/lib/sequel/adapters/shared/postgres.rb +688 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +317 -96
- data/lib/sequel/adapters/sqlite.rb +109 -46
- 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 +31 -27
- data/lib/sequel/adapters/tinytds.rb +177 -25
- 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/split_alter_table.rb +36 -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 +23 -13
- data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
- data/lib/sequel/connection_pool/single.rb +11 -3
- data/lib/sequel/connection_pool/threaded.rb +69 -20
- data/lib/sequel/connection_pool.rb +20 -18
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +66 -29
- 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 +192 -51
- data/lib/sequel/database/query.rb +299 -114
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +310 -69
- 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 +322 -68
- data/lib/sequel/dataset/sql.rb +716 -293
- 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/connection_validator.rb +109 -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 +539 -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 +334 -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 +212 -0
- data/lib/sequel/extensions/pg_range.rb +513 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +576 -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 +137 -16
- 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 +77 -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 +168 -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 +57 -12
- 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/touch.rb +18 -6
- 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 +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +57 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +721 -141
- 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 +53 -39
- data/spec/adapters/mssql_spec.rb +261 -66
- data/spec/adapters/mysql_spec.rb +597 -352
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +2103 -341
- data/spec/adapters/spec_helper.rb +16 -6
- data/spec/adapters/sqlite_spec.rb +237 -76
- data/spec/core/connection_pool_spec.rb +270 -141
- data/spec/core/database_spec.rb +980 -524
- data/spec/core/dataset_spec.rb +1658 -1243
- data/spec/core/expression_filters_spec.rb +741 -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 +227 -33
- 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/connection_validator_spec.rb +118 -0
- 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 +324 -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 +200 -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 +340 -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 +65 -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 +53 -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 +77 -68
- data/spec/extensions/validation_helpers_spec.rb +48 -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 +25 -5
- data/spec/integration/dataset_test.rb +729 -141
- 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 +871 -160
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +377 -57
- data/spec/integration/spec_helper.rb +49 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +40 -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 +223 -81
- data/spec/core/core_sql_spec.rb +0 -451
data/lib/sequel/model/errors.rb
CHANGED
|
@@ -40,7 +40,7 @@ module Sequel
|
|
|
40
40
|
def full_messages
|
|
41
41
|
inject([]) do |m, kv|
|
|
42
42
|
att, errors = *kv
|
|
43
|
-
errors.each {|e| m << "#{Array(att).join(ATTRIBUTE_JOINER)} #{e}"}
|
|
43
|
+
errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(ATTRIBUTE_JOINER)} #{e}")}
|
|
44
44
|
m
|
|
45
45
|
end
|
|
46
46
|
end
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
# Exception class raised when +raise_on_save_failure+ is set and a before hook returns false
|
|
3
|
-
|
|
3
|
+
# or an around hook doesn't call super or yield.
|
|
4
|
+
class HookFailed < Error
|
|
5
|
+
# The Sequel::Model instance related to this error.
|
|
6
|
+
attr_reader :model
|
|
7
|
+
|
|
8
|
+
def initialize(message, model=nil)
|
|
9
|
+
@model = model
|
|
10
|
+
super(message)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Deprecated alias for HookFailed, kept for backwards compatibility
|
|
15
|
+
BeforeHookFailed = HookFailed
|
|
4
16
|
|
|
5
17
|
# Exception class raised when +require_modification+ is set and an UPDATE or DELETE statement to modify the dataset doesn't
|
|
6
18
|
# modify a single row.
|
|
@@ -11,7 +23,18 @@ module Sequel
|
|
|
11
23
|
|
|
12
24
|
# Exception class raised when +raise_on_save_failure+ is set and validation fails
|
|
13
25
|
class ValidationFailed < Error
|
|
26
|
+
# The Sequel::Model object related to this exception.
|
|
27
|
+
attr_reader :model
|
|
28
|
+
|
|
29
|
+
# The Sequel::Model::Errors object related to this exception.
|
|
30
|
+
attr_reader :errors
|
|
31
|
+
|
|
14
32
|
def initialize(errors)
|
|
33
|
+
if errors.is_a?(Sequel::Model)
|
|
34
|
+
@model = errors
|
|
35
|
+
errors = @model.errors
|
|
36
|
+
end
|
|
37
|
+
|
|
15
38
|
if errors.respond_to?(:full_messages)
|
|
16
39
|
@errors = errors
|
|
17
40
|
super(errors.full_messages.join(', '))
|
|
@@ -19,6 +42,5 @@ module Sequel
|
|
|
19
42
|
super
|
|
20
43
|
end
|
|
21
44
|
end
|
|
22
|
-
attr_reader :errors
|
|
23
45
|
end
|
|
24
46
|
end
|
|
@@ -121,7 +121,7 @@ module Sequel
|
|
|
121
121
|
def constantize(s)
|
|
122
122
|
s = s.to_s
|
|
123
123
|
return s.constantize if s.respond_to?(:constantize)
|
|
124
|
-
raise(NameError, "#{inspect} is not a valid constant name!") unless m = VALID_CONSTANT_NAME_REGEXP.match(s
|
|
124
|
+
raise(NameError, "#{s.inspect} is not a valid constant name!") unless m = VALID_CONSTANT_NAME_REGEXP.match(s)
|
|
125
125
|
Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
|
|
126
126
|
end
|
|
127
127
|
|
data/lib/sequel/model.rb
CHANGED
|
@@ -11,9 +11,9 @@ module Sequel
|
|
|
11
11
|
# with the +Database+ in +source+ to create the
|
|
12
12
|
# dataset to use)
|
|
13
13
|
# Dataset :: Sets the dataset for this model to +source+.
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
14
|
+
# other :: Sets the table name for this model to +source+. The
|
|
15
|
+
# class will use the default database for model
|
|
16
|
+
# classes in order to create the dataset.
|
|
17
17
|
#
|
|
18
18
|
# The purpose of this method is to set the dataset/database automatically
|
|
19
19
|
# for a model class, if the table name doesn't match the implicit
|
|
@@ -35,13 +35,18 @@ module Sequel
|
|
|
35
35
|
# dataset # => DB1[:comments]
|
|
36
36
|
# end
|
|
37
37
|
def self.Model(source)
|
|
38
|
-
Model::ANONYMOUS_MODEL_CLASSES[source]
|
|
38
|
+
if Sequel::Model.cache_anonymous_models && (klass = Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source]})
|
|
39
|
+
return klass
|
|
40
|
+
end
|
|
41
|
+
klass = if source.is_a?(Database)
|
|
39
42
|
c = Class.new(Model)
|
|
40
43
|
c.db = source
|
|
41
44
|
c
|
|
42
45
|
else
|
|
43
46
|
Class.new(Model).set_dataset(source)
|
|
44
47
|
end
|
|
48
|
+
Sequel.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source] = klass} if Sequel::Model.cache_anonymous_models
|
|
49
|
+
klass
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
# <tt>Sequel::Model</tt> is an object relational mapper built on top of Sequel core. Each
|
|
@@ -49,14 +54,18 @@ module Sequel
|
|
|
49
54
|
# called directly on the class. Model datasets return rows as model instances,
|
|
50
55
|
# which have fairly standard ORM instance behavior.
|
|
51
56
|
#
|
|
52
|
-
# <tt>Sequel::Model</tt> is built completely out of plugins
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
57
|
+
# <tt>Sequel::Model</tt> is built completely out of plugins. Plugins can override any class,
|
|
58
|
+
# instance, or dataset method defined by a previous plugin and call super to get the default
|
|
59
|
+
# behavior. By default, <tt>Sequel::Model</tt> loads two plugins, <tt>Sequel::Model</tt>
|
|
60
|
+
# (which is itself a plugin) for the base support, and <tt>Sequel::Model::Associations</tt>
|
|
61
|
+
# for the associations support.
|
|
56
62
|
#
|
|
57
63
|
# You can set the +SEQUEL_NO_ASSOCIATIONS+ constant or environment variable to
|
|
58
64
|
# make Sequel not load the associations plugin by default.
|
|
59
65
|
class Model
|
|
66
|
+
# Cache anonymous models created by Sequel::Model()
|
|
67
|
+
@cache_anonymous_models = true
|
|
68
|
+
|
|
60
69
|
# Map that stores model classes created with <tt>Sequel::Model()</tt>, to allow the reopening
|
|
61
70
|
# of classes when dealing with code reloading.
|
|
62
71
|
ANONYMOUS_MODEL_CLASSES = {}
|
|
@@ -69,7 +78,8 @@ module Sequel
|
|
|
69
78
|
EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@db]
|
|
70
79
|
|
|
71
80
|
# Boolean settings that can be modified at the global, class, or instance level.
|
|
72
|
-
BOOLEAN_SETTINGS = [:typecast_empty_string_to_nil, :typecast_on_assignment, :strict_param_setting,
|
|
81
|
+
BOOLEAN_SETTINGS = [:typecast_empty_string_to_nil, :typecast_on_assignment, :strict_param_setting, \
|
|
82
|
+
:raise_on_save_failure, :raise_on_typecast_failure, :require_modification, :use_after_commit_rollback, :use_transactions]
|
|
73
83
|
|
|
74
84
|
# Hooks that are called before an action. Can return false to not do the action. When
|
|
75
85
|
# overriding these, it is recommended to call +super+ as the last line of your method,
|
|
@@ -78,7 +88,13 @@ module Sequel
|
|
|
78
88
|
|
|
79
89
|
# Hooks that are called after an action. When overriding these, it is recommended to call
|
|
80
90
|
# +super+ on the first line of your method, so later hooks are called after earlier hooks.
|
|
81
|
-
AFTER_HOOKS = [:after_initialize, :after_create, :after_update, :after_save, :after_destroy,
|
|
91
|
+
AFTER_HOOKS = [:after_initialize, :after_create, :after_update, :after_save, :after_destroy,
|
|
92
|
+
:after_validation, :after_commit, :after_rollback, :after_destroy_commit, :after_destroy_rollback]
|
|
93
|
+
|
|
94
|
+
# Hooks that are called around an action. If overridden, these methods must call super
|
|
95
|
+
# exactly once if the behavior they wrap is desired. The can be used to rescue exceptions
|
|
96
|
+
# raised by the code they wrap or ensure that some behavior is executed no matter what.
|
|
97
|
+
AROUND_HOOKS = [:around_create, :around_update, :around_save, :around_destroy, :around_validation]
|
|
82
98
|
|
|
83
99
|
# Empty instance methods to create that the user can override to get hook/callback behavior.
|
|
84
100
|
# Just like any other method defined by Sequel, if you override one of these, you should
|
|
@@ -96,7 +112,9 @@ module Sequel
|
|
|
96
112
|
:@restricted_columns=>:dup, :@restrict_primary_key=>nil,
|
|
97
113
|
:@simple_pk=>nil, :@simple_table=>nil, :@strict_param_setting=>nil,
|
|
98
114
|
:@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
|
|
99
|
-
:@raise_on_typecast_failure=>nil, :@plugins=>:dup, :@setter_methods=>nil
|
|
115
|
+
:@raise_on_typecast_failure=>nil, :@plugins=>:dup, :@setter_methods=>nil,
|
|
116
|
+
:@use_after_commit_rollback=>nil, :@fast_pk_lookup_sql=>nil,
|
|
117
|
+
:@fast_instance_delete_sql=>nil}
|
|
100
118
|
|
|
101
119
|
# Regular expression that determines if a method name is normal in the sense that
|
|
102
120
|
# it could be used literally in ruby code without using send. Used to
|
|
@@ -126,6 +144,7 @@ module Sequel
|
|
|
126
144
|
@strict_param_setting = true
|
|
127
145
|
@typecast_empty_string_to_nil = true
|
|
128
146
|
@typecast_on_assignment = true
|
|
147
|
+
@use_after_commit_rollback = true
|
|
129
148
|
@use_transactions = true
|
|
130
149
|
|
|
131
150
|
Sequel.require %w"default_inflections inflections plugins base exceptions errors", "model"
|
|
@@ -16,7 +16,14 @@ module Sequel
|
|
|
16
16
|
# # Make the Album class active_model compliant
|
|
17
17
|
# Album.plugin :active_model
|
|
18
18
|
module ActiveModel
|
|
19
|
-
ClassMethods
|
|
19
|
+
module ClassMethods
|
|
20
|
+
include ::ActiveModel::Naming
|
|
21
|
+
|
|
22
|
+
# Class level cache for to_partial_path.
|
|
23
|
+
def _to_partial_path
|
|
24
|
+
@_to_partial_path ||= "#{underscore(pluralize(to_s))}/#{underscore(demodulize(to_s))}".freeze
|
|
25
|
+
end
|
|
26
|
+
end
|
|
20
27
|
|
|
21
28
|
module InstanceMethods
|
|
22
29
|
# The default string to join composite primary keys with in to_param.
|
|
@@ -56,6 +63,11 @@ module Sequel
|
|
|
56
63
|
k.join(to_param_joiner)
|
|
57
64
|
end
|
|
58
65
|
end
|
|
66
|
+
|
|
67
|
+
# Returns a string identifying the path associated with the object.
|
|
68
|
+
def to_partial_path
|
|
69
|
+
model._to_partial_path
|
|
70
|
+
end
|
|
59
71
|
|
|
60
72
|
private
|
|
61
73
|
|
|
@@ -14,16 +14,13 @@ module Sequel
|
|
|
14
14
|
#
|
|
15
15
|
# Note that it uses the singular form of the association name. Also note
|
|
16
16
|
# that the setter both associates to new primary keys not in the assocation
|
|
17
|
-
# and
|
|
17
|
+
# and disassociates from primary keys not provided to the method.
|
|
18
18
|
#
|
|
19
19
|
# This plugin makes modifications directly to the underlying tables,
|
|
20
20
|
# it does not create or return any model objects, and therefore does
|
|
21
21
|
# not call any callbacks. If you have any association callbacks,
|
|
22
22
|
# you probably should not use the setter methods.
|
|
23
23
|
#
|
|
24
|
-
# This plugin only works with singular primary keys, it does not work
|
|
25
|
-
# with composite primary keys.
|
|
26
|
-
#
|
|
27
24
|
# Usage:
|
|
28
25
|
#
|
|
29
26
|
# # Make all model subclass *_to_many associations have association_pks
|
|
@@ -52,15 +49,85 @@ module Sequel
|
|
|
52
49
|
# a setter that deletes from or inserts into the join table.
|
|
53
50
|
def def_many_to_many(opts)
|
|
54
51
|
super
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
# Grab values from the reflection so that the hash lookup only needs to be
|
|
53
|
+
# done once instead of inside ever method call.
|
|
54
|
+
lk, lpk, rk = opts.values_at(:left_key, :left_primary_key, :right_key)
|
|
55
|
+
|
|
56
|
+
# Add 2 separate implementations of the getter method optimized for the
|
|
57
|
+
# composite and singular left key cases, and 4 separate implementations of the setter
|
|
58
|
+
# method optimized for each combination of composite and singular keys for both
|
|
59
|
+
# the left and right keys.
|
|
60
|
+
if lpk.is_a?(Array)
|
|
61
|
+
def_association_pks_getter(opts) do
|
|
62
|
+
h = {}
|
|
63
|
+
lk.zip(lpk).each{|k, pk| h[k] = send(pk)}
|
|
64
|
+
_join_table_dataset(opts).filter(h).select_map(rk)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if rk.is_a?(Array)
|
|
68
|
+
def_association_pks_setter(opts) do |pks|
|
|
69
|
+
pks = convert_cpk_array(opts, pks)
|
|
70
|
+
checked_transaction do
|
|
71
|
+
lpkv = lpk.map{|k| send(k)}
|
|
72
|
+
ds = _join_table_dataset(opts).filter(lk.zip(lpkv))
|
|
73
|
+
ds.exclude(rk=>pks).delete
|
|
74
|
+
pks -= ds.select_map(rk)
|
|
75
|
+
h = {}
|
|
76
|
+
lk.zip(lpkv).each{|k, v| h[k] = v}
|
|
77
|
+
pks.each do |pk|
|
|
78
|
+
ih = h.dup
|
|
79
|
+
rk.zip(pk).each{|k, v| ih[k] = v}
|
|
80
|
+
ds.insert(ih)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
else
|
|
85
|
+
def_association_pks_setter(opts) do |pks|
|
|
86
|
+
pks = convert_pk_array(opts, pks)
|
|
87
|
+
checked_transaction do
|
|
88
|
+
lpkv = lpk.map{|k| send(k)}
|
|
89
|
+
ds = _join_table_dataset(opts).filter(lk.zip(lpkv))
|
|
90
|
+
ds.exclude(rk=>pks).delete
|
|
91
|
+
pks -= ds.select_map(rk)
|
|
92
|
+
h = {}
|
|
93
|
+
lk.zip(lpkv).each{|k, v| h[k] = v}
|
|
94
|
+
pks.each do |pk|
|
|
95
|
+
ds.insert(h.merge(rk=>pk))
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
def_association_pks_getter(opts) do
|
|
102
|
+
_join_table_dataset(opts).filter(lk=>send(lpk)).select_map(rk)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if rk.is_a?(Array)
|
|
106
|
+
def_association_pks_setter(opts) do |pks|
|
|
107
|
+
pks = convert_cpk_array(opts, pks)
|
|
108
|
+
checked_transaction do
|
|
109
|
+
lpkv = send(lpk)
|
|
110
|
+
ds = _join_table_dataset(opts).filter(lk=>lpkv)
|
|
111
|
+
ds.exclude(rk=>pks).delete
|
|
112
|
+
pks -= ds.select_map(rk)
|
|
113
|
+
pks.each do |pk|
|
|
114
|
+
h = {lk=>lpkv}
|
|
115
|
+
rk.zip(pk).each{|k, v| h[k] = v}
|
|
116
|
+
ds.insert(h)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
def_association_pks_setter(opts) do |pks|
|
|
122
|
+
pks = convert_pk_array(opts, pks)
|
|
123
|
+
checked_transaction do
|
|
124
|
+
lpkv = send(lpk)
|
|
125
|
+
ds = _join_table_dataset(opts).filter(lk=>lpkv)
|
|
126
|
+
ds.exclude(rk=>pks).delete
|
|
127
|
+
pks -= ds.select_map(rk)
|
|
128
|
+
pks.each{|pk| ds.insert(lk=>lpkv, rk=>pk)}
|
|
129
|
+
end
|
|
130
|
+
end
|
|
64
131
|
end
|
|
65
132
|
end
|
|
66
133
|
end
|
|
@@ -70,15 +137,69 @@ module Sequel
|
|
|
70
137
|
def def_one_to_many(opts)
|
|
71
138
|
super
|
|
72
139
|
return if opts[:type] == :one_to_one
|
|
140
|
+
|
|
141
|
+
key = opts[:key]
|
|
142
|
+
|
|
73
143
|
def_association_pks_getter(opts) do
|
|
74
|
-
send(opts.dataset_method).select_map(opts
|
|
144
|
+
send(opts.dataset_method).select_map(opts.associated_class.primary_key)
|
|
75
145
|
end
|
|
146
|
+
|
|
76
147
|
def_association_pks_setter(opts) do |pks|
|
|
148
|
+
primary_key = opts.associated_class.primary_key
|
|
149
|
+
|
|
150
|
+
pks = if primary_key.is_a?(Array)
|
|
151
|
+
convert_cpk_array(opts, pks)
|
|
152
|
+
else
|
|
153
|
+
convert_pk_array(opts, pks)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
pkh = {primary_key=>pks}
|
|
157
|
+
|
|
158
|
+
if key.is_a?(Array)
|
|
159
|
+
h = {}
|
|
160
|
+
nh = {}
|
|
161
|
+
key.zip(pk).each do|k, v|
|
|
162
|
+
h[k] = v
|
|
163
|
+
nh[k] = nil
|
|
164
|
+
end
|
|
165
|
+
else
|
|
166
|
+
h = {key=>pk}
|
|
167
|
+
nh = {key=>nil}
|
|
168
|
+
end
|
|
169
|
+
|
|
77
170
|
checked_transaction do
|
|
78
171
|
ds = send(opts.dataset_method)
|
|
79
|
-
ds.unfiltered.filter(
|
|
80
|
-
ds.exclude(
|
|
172
|
+
ds.unfiltered.filter(pkh).update(h)
|
|
173
|
+
ds.exclude(pkh).update(nh)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
module InstanceMethods
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
# If any of associated class's composite primary key column types is integer,
|
|
183
|
+
# typecast the appropriate values to integer before using them.
|
|
184
|
+
def convert_cpk_array(opts, cpks)
|
|
185
|
+
if klass = opts.associated_class and sch = klass.db_schema and (cols = sch.values_at(*klass.primary_key)).all? and (convs = cols.map{|c| c[:type] == :integer}).any?
|
|
186
|
+
cpks.map do |cpk|
|
|
187
|
+
cpk.zip(convs).map do |pk, conv|
|
|
188
|
+
conv ? model.db.typecast_value(:integer, pk) : pk
|
|
189
|
+
end
|
|
81
190
|
end
|
|
191
|
+
else
|
|
192
|
+
cpks
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# If the associated class's primary key column type is integer,
|
|
197
|
+
# typecast all provided values to integer before using them.
|
|
198
|
+
def convert_pk_array(opts, pks)
|
|
199
|
+
if klass = opts.associated_class and sch = klass.db_schema and col = sch[klass.primary_key] and col[:type] == :integer
|
|
200
|
+
pks.map{|pk| model.db.typecast_value(:integer, pk)}
|
|
201
|
+
else
|
|
202
|
+
pks
|
|
82
203
|
end
|
|
83
204
|
end
|
|
84
205
|
end
|
|
@@ -53,9 +53,21 @@ module Sequel
|
|
|
53
53
|
# The time to live for the cache store, in seconds.
|
|
54
54
|
attr_reader :cache_ttl
|
|
55
55
|
|
|
56
|
-
#
|
|
57
|
-
def
|
|
58
|
-
|
|
56
|
+
# Delete the cached object with the given primary key.
|
|
57
|
+
def cache_delete_pk(pk)
|
|
58
|
+
cache_delete(cache_key(pk))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Return the cached object with the given primary key,
|
|
62
|
+
# or nil if no such object is in the cache.
|
|
63
|
+
def cache_get_pk(pk)
|
|
64
|
+
cache_get(cache_key(pk))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Return a key string for the given primary key.
|
|
68
|
+
def cache_key(pk)
|
|
69
|
+
raise(Error, 'no primary key for this record') unless pk.is_a?(Array) ? pk.all? : pk
|
|
70
|
+
"#{self}:#{Array(pk).join(',')}"
|
|
59
71
|
end
|
|
60
72
|
|
|
61
73
|
# Copy the necessary class instance variables to the subclass.
|
|
@@ -69,8 +81,13 @@ module Sequel
|
|
|
69
81
|
@cache_ttl = ttl
|
|
70
82
|
@cache_ignore_exceptions = cache_ignore_exceptions
|
|
71
83
|
end
|
|
72
|
-
end
|
|
84
|
+
end
|
|
73
85
|
|
|
86
|
+
# Set the time to live for the cache store, in seconds (default is 3600, # so 1 hour).
|
|
87
|
+
def set_cache_ttl(ttl)
|
|
88
|
+
@cache_ttl = ttl
|
|
89
|
+
end
|
|
90
|
+
|
|
74
91
|
private
|
|
75
92
|
|
|
76
93
|
# Delete the entry with the matching key from the cache
|
|
@@ -79,6 +96,8 @@ module Sequel
|
|
|
79
96
|
nil
|
|
80
97
|
end
|
|
81
98
|
|
|
99
|
+
# Returned the cached object, or nil if the object was not
|
|
100
|
+
# in the cached
|
|
82
101
|
def cache_get(ck)
|
|
83
102
|
if @cache_ignore_exceptions
|
|
84
103
|
@cache_store.get(ck) rescue nil
|
|
@@ -87,11 +106,6 @@ module Sequel
|
|
|
87
106
|
end
|
|
88
107
|
end
|
|
89
108
|
|
|
90
|
-
# Return a key string for the pk
|
|
91
|
-
def cache_key(pk)
|
|
92
|
-
"#{self}:#{Array(pk).join(',')}"
|
|
93
|
-
end
|
|
94
|
-
|
|
95
109
|
# Set the object in the cache_store with the given key for cache_ttl seconds.
|
|
96
110
|
def cache_set(ck, obj)
|
|
97
111
|
@cache_store.set(ck, obj, @cache_ttl)
|
|
@@ -120,14 +134,7 @@ module Sequel
|
|
|
120
134
|
# primary key value(s) for the object. If the model does not have a primary
|
|
121
135
|
# key, raise an Error.
|
|
122
136
|
def cache_key
|
|
123
|
-
|
|
124
|
-
pk = case key
|
|
125
|
-
when Array
|
|
126
|
-
key.collect{|k| @values[k]}
|
|
127
|
-
else
|
|
128
|
-
@values[key] || (raise Error, 'no primary key for this record')
|
|
129
|
-
end
|
|
130
|
-
model.send(:cache_key, pk)
|
|
137
|
+
model.cache_key(pk)
|
|
131
138
|
end
|
|
132
139
|
|
|
133
140
|
# Remove the object from the cache when deleting
|
|
@@ -140,7 +147,7 @@ module Sequel
|
|
|
140
147
|
|
|
141
148
|
# Delete this object from the cache
|
|
142
149
|
def cache_delete
|
|
143
|
-
model.
|
|
150
|
+
model.cache_delete_pk(pk)
|
|
144
151
|
end
|
|
145
152
|
end
|
|
146
153
|
end
|
|
@@ -90,9 +90,9 @@ module Sequel
|
|
|
90
90
|
@cti_columns = {table_name=>columns}
|
|
91
91
|
@cti_table_map = opts[:table_map] || {}
|
|
92
92
|
dataset.row_proc = if key
|
|
93
|
-
lambda{|r| (m.call(r[key]) rescue model).
|
|
93
|
+
lambda{|r| (m.call(r[key]) rescue model).call(r)}
|
|
94
94
|
else
|
|
95
|
-
|
|
95
|
+
model
|
|
96
96
|
end
|
|
97
97
|
end
|
|
98
98
|
end
|
|
@@ -152,9 +152,9 @@ module Sequel
|
|
|
152
152
|
subclass.instance_eval do
|
|
153
153
|
m = method(:constantize)
|
|
154
154
|
dataset.row_proc = if cti_key
|
|
155
|
-
lambda{|r| (m.call(r[ck]) rescue subclass).
|
|
155
|
+
lambda{|r| (m.call(r[ck]) rescue subclass).call(r)}
|
|
156
156
|
else
|
|
157
|
-
|
|
157
|
+
subclass
|
|
158
158
|
end
|
|
159
159
|
(columns - [cbm.primary_key]).each{|a| define_lazy_attribute_getter(a)}
|
|
160
160
|
cti_tables.reverse.each do |table|
|
|
@@ -1,20 +1,53 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
module Plugins
|
|
3
|
-
# The composition plugin allows you to easily define
|
|
4
|
-
#
|
|
5
|
-
# is composed of other getters and decomposed to other setters.
|
|
3
|
+
# The composition plugin allows you to easily define a virtual
|
|
4
|
+
# attribute where the backing data is composed of other columns.
|
|
6
5
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# with
|
|
6
|
+
# There are two ways to use the plugin. One way is with the
|
|
7
|
+
# :mapping option. A simple example of this is when you have a
|
|
8
|
+
# database table with separate columns for year, month, and day,
|
|
9
|
+
# but where you want to deal with Date objects in your ruby code.
|
|
10
|
+
# This can be handled with:
|
|
11
11
|
#
|
|
12
12
|
# Album.plugin :composition
|
|
13
13
|
# Album.composition :date, :mapping=>[:year, :month, :day]
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# :
|
|
15
|
+
# With the :mapping option, you can provide a :class option
|
|
16
|
+
# that gives the class to use, but if that is not provided, it
|
|
17
|
+
# is inferred from the name of the composition (e.g. :date -> Date).
|
|
18
|
+
# When the <tt>date</tt> method is called, it will return a
|
|
19
|
+
# Date object by calling:
|
|
20
|
+
#
|
|
21
|
+
# Date.new(year, month, day)
|
|
22
|
+
#
|
|
23
|
+
# When saving the object, if the date composition has been used
|
|
24
|
+
# (by calling either the getter or setter method), it will
|
|
25
|
+
# populate the related columns of the object before saving:
|
|
26
|
+
#
|
|
27
|
+
# self.year = date.year
|
|
28
|
+
# self.month = date.month
|
|
29
|
+
# self.day = date.day
|
|
30
|
+
#
|
|
31
|
+
# The :mapping option is just a shortcut that works in particular
|
|
32
|
+
# cases. To handle any case, you can define a custom :composer
|
|
33
|
+
# and :decomposer procs. The :composer proc will be instance_evaled
|
|
34
|
+
# the first time the getter is called, and the :decomposer proc
|
|
35
|
+
# will be instance_evaled before saving. The above example could
|
|
36
|
+
# also be implemented as:
|
|
37
|
+
#
|
|
38
|
+
# Album.composition :date,
|
|
39
|
+
# :composer=>proc{Date.new(year, month, day) if year || month || day},
|
|
40
|
+
# :decomposer=>(proc do
|
|
41
|
+
# if d = compositions[:date]
|
|
42
|
+
# self.year = d.year
|
|
43
|
+
# self.month = d.month
|
|
44
|
+
# self.day = d.day
|
|
45
|
+
# else
|
|
46
|
+
# self.year = nil
|
|
47
|
+
# self.month = nil
|
|
48
|
+
# self.day = nil
|
|
49
|
+
# end
|
|
50
|
+
# end)
|
|
18
51
|
#
|
|
19
52
|
# Note that when using the composition object, you should not
|
|
20
53
|
# modify the underlying columns if you are also instantiating
|
|
@@ -117,9 +150,8 @@ module Sequel
|
|
|
117
150
|
module InstanceMethods
|
|
118
151
|
# Clear the cached compositions when refreshing.
|
|
119
152
|
def _refresh(ds)
|
|
120
|
-
|
|
153
|
+
super
|
|
121
154
|
compositions.clear
|
|
122
|
-
v
|
|
123
155
|
end
|
|
124
156
|
|
|
125
157
|
# For each composition, set the columns in the model class based
|