sequel 4.26.0 → 5.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG +405 -5656
- data/MIT-LICENSE +1 -1
- data/README.rdoc +232 -157
- data/bin/sequel +32 -9
- data/doc/advanced_associations.rdoc +252 -188
- data/doc/association_basics.rdoc +231 -273
- data/doc/bin_sequel.rdoc +5 -3
- data/doc/cheat_sheet.rdoc +75 -48
- data/doc/code_order.rdoc +28 -10
- data/doc/core_extensions.rdoc +104 -63
- data/doc/dataset_basics.rdoc +12 -21
- data/doc/dataset_filtering.rdoc +99 -86
- data/doc/extensions.rdoc +3 -10
- data/doc/mass_assignment.rdoc +74 -31
- data/doc/migration.rdoc +72 -46
- data/doc/model_dataset_method_design.rdoc +129 -0
- data/doc/model_hooks.rdoc +15 -25
- data/doc/model_plugins.rdoc +12 -12
- data/doc/mssql_stored_procedures.rdoc +3 -3
- data/doc/object_model.rdoc +59 -69
- data/doc/opening_databases.rdoc +84 -94
- data/doc/postgresql.rdoc +268 -38
- data/doc/prepared_statements.rdoc +29 -24
- data/doc/querying.rdoc +184 -164
- data/doc/reflection.rdoc +5 -6
- data/doc/release_notes/5.0.0.txt +159 -0
- data/doc/release_notes/5.1.0.txt +31 -0
- data/doc/release_notes/5.10.0.txt +84 -0
- data/doc/release_notes/5.11.0.txt +83 -0
- data/doc/release_notes/5.12.0.txt +141 -0
- data/doc/release_notes/5.13.0.txt +27 -0
- data/doc/release_notes/5.14.0.txt +63 -0
- data/doc/release_notes/5.15.0.txt +39 -0
- data/doc/release_notes/5.16.0.txt +110 -0
- data/doc/release_notes/5.17.0.txt +31 -0
- data/doc/release_notes/5.18.0.txt +69 -0
- data/doc/release_notes/5.19.0.txt +28 -0
- data/doc/release_notes/5.2.0.txt +33 -0
- data/doc/release_notes/5.20.0.txt +89 -0
- data/doc/release_notes/5.21.0.txt +87 -0
- data/doc/release_notes/5.22.0.txt +48 -0
- data/doc/release_notes/5.23.0.txt +56 -0
- data/doc/release_notes/5.24.0.txt +56 -0
- data/doc/release_notes/5.25.0.txt +32 -0
- data/doc/release_notes/5.26.0.txt +35 -0
- data/doc/release_notes/5.27.0.txt +21 -0
- data/doc/release_notes/5.28.0.txt +16 -0
- data/doc/release_notes/5.29.0.txt +22 -0
- data/doc/release_notes/5.3.0.txt +121 -0
- data/doc/release_notes/5.30.0.txt +20 -0
- data/doc/release_notes/5.31.0.txt +148 -0
- data/doc/release_notes/5.32.0.txt +46 -0
- data/doc/release_notes/5.33.0.txt +24 -0
- data/doc/release_notes/5.34.0.txt +40 -0
- data/doc/release_notes/5.35.0.txt +56 -0
- data/doc/release_notes/5.36.0.txt +60 -0
- data/doc/release_notes/5.37.0.txt +30 -0
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/release_notes/5.5.0.txt +61 -0
- data/doc/release_notes/5.6.0.txt +31 -0
- data/doc/release_notes/5.7.0.txt +108 -0
- data/doc/release_notes/5.8.0.txt +170 -0
- data/doc/release_notes/5.9.0.txt +99 -0
- data/doc/schema_modification.rdoc +102 -77
- data/doc/security.rdoc +160 -87
- data/doc/sharding.rdoc +74 -47
- data/doc/sql.rdoc +135 -122
- data/doc/testing.rdoc +34 -18
- data/doc/thread_safety.rdoc +2 -4
- data/doc/transactions.rdoc +101 -19
- data/doc/validations.rdoc +64 -51
- data/doc/virtual_rows.rdoc +90 -109
- data/lib/sequel.rb +3 -1
- data/lib/sequel/adapters/ado.rb +154 -22
- data/lib/sequel/adapters/ado/access.rb +21 -21
- data/lib/sequel/adapters/ado/mssql.rb +8 -15
- data/lib/sequel/adapters/amalgalite.rb +17 -25
- data/lib/sequel/adapters/ibmdb.rb +52 -58
- data/lib/sequel/adapters/jdbc.rb +149 -127
- data/lib/sequel/adapters/jdbc/db2.rb +32 -40
- data/lib/sequel/adapters/jdbc/derby.rb +56 -58
- data/lib/sequel/adapters/jdbc/h2.rb +40 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +22 -33
- data/lib/sequel/adapters/jdbc/jtds.rb +4 -10
- data/lib/sequel/adapters/jdbc/mssql.rb +6 -12
- data/lib/sequel/adapters/jdbc/mysql.rb +17 -18
- data/lib/sequel/adapters/jdbc/oracle.rb +25 -19
- data/lib/sequel/adapters/jdbc/postgresql.rb +90 -69
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +14 -24
- data/lib/sequel/adapters/jdbc/sqlite.rb +50 -12
- data/lib/sequel/adapters/jdbc/sqlserver.rb +36 -9
- data/lib/sequel/adapters/jdbc/transactions.rb +25 -39
- data/lib/sequel/adapters/mock.rb +104 -113
- data/lib/sequel/adapters/mysql.rb +42 -61
- data/lib/sequel/adapters/mysql2.rb +126 -35
- data/lib/sequel/adapters/odbc.rb +21 -28
- data/lib/sequel/adapters/odbc/db2.rb +3 -1
- data/lib/sequel/adapters/odbc/mssql.rb +11 -15
- data/lib/sequel/adapters/odbc/oracle.rb +11 -0
- data/lib/sequel/adapters/oracle.rb +62 -68
- data/lib/sequel/adapters/postgres.rb +257 -311
- data/lib/sequel/adapters/postgresql.rb +3 -1
- data/lib/sequel/adapters/shared/access.rb +75 -79
- data/lib/sequel/adapters/shared/db2.rb +96 -74
- data/lib/sequel/adapters/shared/mssql.rb +258 -213
- data/lib/sequel/adapters/shared/mysql.rb +284 -216
- data/lib/sequel/adapters/shared/oracle.rb +175 -60
- data/lib/sequel/adapters/shared/postgres.rb +829 -383
- data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -127
- data/lib/sequel/adapters/shared/sqlite.rb +382 -159
- data/lib/sequel/adapters/sqlanywhere.rb +53 -38
- data/lib/sequel/adapters/sqlite.rb +111 -105
- data/lib/sequel/adapters/tinytds.rb +38 -46
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -9
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -5
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
- data/lib/sequel/adapters/utils/replace.rb +3 -4
- data/lib/sequel/adapters/utils/split_alter_table.rb +2 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
- data/lib/sequel/ast_transformer.rb +13 -89
- data/lib/sequel/connection_pool.rb +54 -26
- data/lib/sequel/connection_pool/sharded_single.rb +19 -12
- data/lib/sequel/connection_pool/sharded_threaded.rb +160 -111
- data/lib/sequel/connection_pool/single.rb +21 -12
- data/lib/sequel/connection_pool/threaded.rb +137 -119
- data/lib/sequel/core.rb +352 -320
- data/lib/sequel/database.rb +19 -2
- data/lib/sequel/database/connecting.rb +70 -55
- data/lib/sequel/database/dataset.rb +15 -5
- data/lib/sequel/database/dataset_defaults.rb +20 -102
- data/lib/sequel/database/features.rb +20 -4
- data/lib/sequel/database/logging.rb +25 -7
- data/lib/sequel/database/misc.rb +132 -118
- data/lib/sequel/database/query.rb +51 -28
- data/lib/sequel/database/schema_generator.rb +188 -75
- data/lib/sequel/database/schema_methods.rb +161 -92
- data/lib/sequel/database/transactions.rb +260 -58
- data/lib/sequel/dataset.rb +28 -12
- data/lib/sequel/dataset/actions.rb +354 -170
- data/lib/sequel/dataset/dataset_module.rb +46 -0
- data/lib/sequel/dataset/features.rb +81 -34
- data/lib/sequel/dataset/graph.rb +82 -58
- data/lib/sequel/dataset/misc.rb +139 -47
- data/lib/sequel/dataset/placeholder_literalizer.rb +66 -26
- data/lib/sequel/dataset/prepared_statements.rb +188 -85
- data/lib/sequel/dataset/query.rb +428 -214
- data/lib/sequel/dataset/sql.rb +446 -339
- data/lib/sequel/deprecated.rb +14 -2
- data/lib/sequel/exceptions.rb +48 -16
- data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
- data/lib/sequel/extensions/_model_pg_row.rb +43 -0
- data/lib/sequel/extensions/_pretty_table.rb +10 -9
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +15 -11
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/blank.rb +2 -0
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/columns_introspection.rb +9 -4
- data/lib/sequel/extensions/connection_expiration.rb +99 -0
- data/lib/sequel/extensions/connection_validator.rb +26 -13
- data/lib/sequel/extensions/constant_sql_override.rb +65 -0
- data/lib/sequel/extensions/constraint_validations.rb +93 -38
- data/lib/sequel/extensions/core_extensions.rb +45 -53
- data/lib/sequel/extensions/core_refinements.rb +44 -46
- data/lib/sequel/extensions/current_datetime_timestamp.rb +5 -4
- data/lib/sequel/extensions/dataset_source_alias.rb +4 -0
- data/lib/sequel/extensions/date_arithmetic.rb +42 -16
- data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +94 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -3
- data/lib/sequel/extensions/error_sql.rb +7 -3
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +14 -15
- data/lib/sequel/extensions/exclude_or_null.rb +68 -0
- data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
- data/lib/sequel/extensions/freeze_datasets.rb +3 -0
- data/lib/sequel/extensions/from_block.rb +2 -31
- data/lib/sequel/extensions/graph_each.rb +19 -6
- data/lib/sequel/extensions/identifier_mangling.rb +180 -0
- data/lib/sequel/extensions/implicit_subquery.rb +48 -0
- data/lib/sequel/extensions/index_caching.rb +109 -0
- data/lib/sequel/extensions/inflector.rb +8 -4
- data/lib/sequel/extensions/integer64.rb +32 -0
- data/lib/sequel/extensions/looser_typecasting.rb +19 -9
- data/lib/sequel/extensions/migration.rb +132 -80
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +4 -0
- data/lib/sequel/extensions/named_timezones.rb +88 -23
- data/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +12 -8
- data/lib/sequel/extensions/pagination.rb +35 -28
- data/lib/sequel/extensions/pg_array.rb +227 -316
- data/lib/sequel/extensions/pg_array_ops.rb +19 -7
- data/lib/sequel/extensions/pg_enum.rb +69 -24
- data/lib/sequel/extensions/pg_extended_date_support.rb +250 -0
- data/lib/sequel/extensions/pg_hstore.rb +50 -59
- data/lib/sequel/extensions/pg_hstore_ops.rb +9 -3
- data/lib/sequel/extensions/pg_inet.rb +34 -15
- data/lib/sequel/extensions/pg_inet_ops.rb +5 -1
- data/lib/sequel/extensions/pg_interval.rb +26 -26
- data/lib/sequel/extensions/pg_json.rb +422 -141
- data/lib/sequel/extensions/pg_json_ops.rb +248 -9
- data/lib/sequel/extensions/pg_loose_count.rb +5 -1
- data/lib/sequel/extensions/pg_range.rb +162 -146
- data/lib/sequel/extensions/pg_range_ops.rb +10 -5
- data/lib/sequel/extensions/pg_row.rb +53 -87
- data/lib/sequel/extensions/pg_row_ops.rb +36 -13
- data/lib/sequel/extensions/pg_static_cache_updater.rb +6 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
- data/lib/sequel/extensions/pretty_table.rb +4 -0
- data/lib/sequel/extensions/query.rb +12 -7
- data/lib/sequel/extensions/round_timestamps.rb +6 -9
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +59 -0
- data/lib/sequel/extensions/schema_caching.rb +14 -1
- data/lib/sequel/extensions/schema_dumper.rb +83 -55
- data/lib/sequel/extensions/select_remove.rb +8 -4
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
- data/lib/sequel/extensions/server_block.rb +50 -17
- data/lib/sequel/extensions/server_logging.rb +61 -0
- data/lib/sequel/extensions/split_array_nil.rb +8 -4
- data/lib/sequel/extensions/sql_comments.rb +96 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -1
- data/lib/sequel/extensions/string_agg.rb +181 -0
- data/lib/sequel/extensions/string_date_time.rb +2 -0
- data/lib/sequel/extensions/symbol_aref.rb +53 -0
- data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
- data/lib/sequel/extensions/symbol_as.rb +23 -0
- data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
- data/lib/sequel/extensions/synchronize_sql.rb +45 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +4 -0
- data/lib/sequel/extensions/to_dot.rb +15 -5
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model.rb +36 -126
- data/lib/sequel/model/associations.rb +850 -257
- data/lib/sequel/model/base.rb +652 -764
- data/lib/sequel/model/dataset_module.rb +13 -10
- data/lib/sequel/model/default_inflections.rb +3 -1
- data/lib/sequel/model/errors.rb +3 -3
- data/lib/sequel/model/exceptions.rb +12 -12
- data/lib/sequel/model/inflections.rb +8 -19
- data/lib/sequel/model/plugins.rb +111 -0
- data/lib/sequel/plugins/accessed_columns.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +32 -7
- data/lib/sequel/plugins/after_initialize.rb +3 -1
- data/lib/sequel/plugins/association_dependencies.rb +27 -18
- data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
- data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
- data/lib/sequel/plugins/association_pks.rb +181 -83
- data/lib/sequel/plugins/association_proxies.rb +33 -9
- data/lib/sequel/plugins/auto_validations.rb +58 -23
- data/lib/sequel/plugins/before_after_save.rb +8 -0
- data/lib/sequel/plugins/blacklist_security.rb +23 -12
- data/lib/sequel/plugins/boolean_readers.rb +9 -6
- data/lib/sequel/plugins/boolean_subsets.rb +64 -0
- data/lib/sequel/plugins/caching.rb +27 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +192 -94
- data/lib/sequel/plugins/column_conflicts.rb +18 -3
- data/lib/sequel/plugins/column_select.rb +9 -5
- data/lib/sequel/plugins/columns_updated.rb +42 -0
- data/lib/sequel/plugins/composition.rb +36 -24
- data/lib/sequel/plugins/constraint_validations.rb +37 -16
- data/lib/sequel/plugins/csv_serializer.rb +58 -35
- data/lib/sequel/plugins/dataset_associations.rb +60 -18
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/defaults_setter.rb +74 -13
- data/lib/sequel/plugins/delay_add_association.rb +4 -1
- data/lib/sequel/plugins/dirty.rb +65 -24
- data/lib/sequel/plugins/eager_each.rb +27 -3
- data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
- data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
- data/lib/sequel/plugins/error_splitter.rb +19 -12
- data/lib/sequel/plugins/finder.rb +246 -0
- data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
- data/lib/sequel/plugins/force_encoding.rb +9 -12
- data/lib/sequel/plugins/hook_class_methods.rb +39 -54
- data/lib/sequel/plugins/input_transformer.rb +20 -10
- data/lib/sequel/plugins/insert_conflict.rb +72 -0
- data/lib/sequel/plugins/insert_returning_select.rb +4 -2
- data/lib/sequel/plugins/instance_filters.rb +12 -8
- data/lib/sequel/plugins/instance_hooks.rb +36 -17
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/inverted_subsets.rb +24 -13
- data/lib/sequel/plugins/json_serializer.rb +123 -47
- data/lib/sequel/plugins/lazy_attributes.rb +20 -14
- data/lib/sequel/plugins/list.rb +40 -26
- data/lib/sequel/plugins/many_through_many.rb +28 -12
- data/lib/sequel/plugins/modification_detection.rb +17 -5
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -5
- data/lib/sequel/plugins/nested_attributes.rb +55 -28
- data/lib/sequel/plugins/optimistic_locking.rb +5 -3
- data/lib/sequel/plugins/pg_array_associations.rb +52 -18
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +348 -0
- data/lib/sequel/plugins/pg_row.rb +7 -51
- data/lib/sequel/plugins/prepared_statements.rb +53 -72
- data/lib/sequel/plugins/prepared_statements_safe.rb +13 -5
- data/lib/sequel/plugins/rcte_tree.rb +43 -63
- data/lib/sequel/plugins/serialization.rb +37 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +3 -1
- data/lib/sequel/plugins/sharding.rb +17 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +62 -28
- data/lib/sequel/plugins/singular_table_names.rb +2 -0
- data/lib/sequel/plugins/skip_create_refresh.rb +5 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/split_values.rb +13 -6
- data/lib/sequel/plugins/static_cache.rb +79 -53
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +5 -3
- data/lib/sequel/plugins/subclasses.rb +20 -2
- data/lib/sequel/plugins/subset_conditions.rb +48 -0
- data/lib/sequel/plugins/table_select.rb +4 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +120 -6
- data/lib/sequel/plugins/throw_failures.rb +110 -0
- data/lib/sequel/plugins/timestamps.rb +22 -8
- data/lib/sequel/plugins/touch.rb +21 -8
- data/lib/sequel/plugins/tree.rb +57 -30
- data/lib/sequel/plugins/typecast_on_load.rb +14 -4
- data/lib/sequel/plugins/unlimited_update.rb +3 -7
- data/lib/sequel/plugins/update_or_create.rb +6 -4
- data/lib/sequel/plugins/update_primary_key.rb +3 -1
- data/lib/sequel/plugins/update_refresh.rb +28 -15
- data/lib/sequel/plugins/uuid.rb +70 -0
- data/lib/sequel/plugins/validate_associated.rb +20 -0
- data/lib/sequel/plugins/validation_class_methods.rb +40 -19
- data/lib/sequel/plugins/validation_contexts.rb +49 -0
- data/lib/sequel/plugins/validation_helpers.rb +49 -31
- data/lib/sequel/plugins/whitelist_security.rb +122 -0
- data/lib/sequel/plugins/xml_serializer.rb +31 -30
- data/lib/sequel/sql.rb +479 -329
- data/lib/sequel/timezones.rb +62 -32
- data/lib/sequel/version.rb +10 -3
- metadata +177 -477
- data/Rakefile +0 -165
- data/doc/active_record.rdoc +0 -912
- data/doc/release_notes/1.0.txt +0 -38
- data/doc/release_notes/1.1.txt +0 -143
- data/doc/release_notes/1.3.txt +0 -101
- data/doc/release_notes/1.4.0.txt +0 -53
- data/doc/release_notes/1.5.0.txt +0 -155
- data/doc/release_notes/2.0.0.txt +0 -298
- data/doc/release_notes/2.1.0.txt +0 -271
- data/doc/release_notes/2.10.0.txt +0 -328
- data/doc/release_notes/2.11.0.txt +0 -215
- data/doc/release_notes/2.12.0.txt +0 -534
- data/doc/release_notes/2.2.0.txt +0 -253
- data/doc/release_notes/2.3.0.txt +0 -88
- data/doc/release_notes/2.4.0.txt +0 -106
- data/doc/release_notes/2.5.0.txt +0 -137
- data/doc/release_notes/2.6.0.txt +0 -157
- data/doc/release_notes/2.7.0.txt +0 -166
- data/doc/release_notes/2.8.0.txt +0 -171
- data/doc/release_notes/2.9.0.txt +0 -97
- data/doc/release_notes/3.0.0.txt +0 -221
- data/doc/release_notes/3.1.0.txt +0 -406
- data/doc/release_notes/3.10.0.txt +0 -286
- data/doc/release_notes/3.11.0.txt +0 -254
- data/doc/release_notes/3.12.0.txt +0 -304
- data/doc/release_notes/3.13.0.txt +0 -210
- data/doc/release_notes/3.14.0.txt +0 -118
- data/doc/release_notes/3.15.0.txt +0 -78
- data/doc/release_notes/3.16.0.txt +0 -45
- data/doc/release_notes/3.17.0.txt +0 -58
- data/doc/release_notes/3.18.0.txt +0 -120
- data/doc/release_notes/3.19.0.txt +0 -67
- data/doc/release_notes/3.2.0.txt +0 -268
- data/doc/release_notes/3.20.0.txt +0 -41
- data/doc/release_notes/3.21.0.txt +0 -87
- data/doc/release_notes/3.22.0.txt +0 -39
- data/doc/release_notes/3.23.0.txt +0 -172
- data/doc/release_notes/3.24.0.txt +0 -420
- data/doc/release_notes/3.25.0.txt +0 -88
- data/doc/release_notes/3.26.0.txt +0 -88
- data/doc/release_notes/3.27.0.txt +0 -82
- data/doc/release_notes/3.28.0.txt +0 -304
- data/doc/release_notes/3.29.0.txt +0 -459
- data/doc/release_notes/3.3.0.txt +0 -192
- data/doc/release_notes/3.30.0.txt +0 -135
- data/doc/release_notes/3.31.0.txt +0 -146
- data/doc/release_notes/3.32.0.txt +0 -202
- data/doc/release_notes/3.33.0.txt +0 -157
- data/doc/release_notes/3.34.0.txt +0 -671
- data/doc/release_notes/3.35.0.txt +0 -144
- data/doc/release_notes/3.36.0.txt +0 -245
- data/doc/release_notes/3.37.0.txt +0 -338
- data/doc/release_notes/3.38.0.txt +0 -234
- data/doc/release_notes/3.39.0.txt +0 -237
- data/doc/release_notes/3.4.0.txt +0 -325
- data/doc/release_notes/3.40.0.txt +0 -73
- data/doc/release_notes/3.41.0.txt +0 -155
- data/doc/release_notes/3.42.0.txt +0 -74
- data/doc/release_notes/3.43.0.txt +0 -105
- data/doc/release_notes/3.44.0.txt +0 -152
- data/doc/release_notes/3.45.0.txt +0 -179
- data/doc/release_notes/3.46.0.txt +0 -122
- data/doc/release_notes/3.47.0.txt +0 -270
- data/doc/release_notes/3.48.0.txt +0 -477
- data/doc/release_notes/3.5.0.txt +0 -510
- data/doc/release_notes/3.6.0.txt +0 -366
- data/doc/release_notes/3.7.0.txt +0 -179
- data/doc/release_notes/3.8.0.txt +0 -151
- data/doc/release_notes/3.9.0.txt +0 -233
- data/doc/release_notes/4.0.0.txt +0 -262
- data/doc/release_notes/4.1.0.txt +0 -85
- data/doc/release_notes/4.10.0.txt +0 -226
- data/doc/release_notes/4.11.0.txt +0 -147
- data/doc/release_notes/4.12.0.txt +0 -105
- data/doc/release_notes/4.13.0.txt +0 -169
- data/doc/release_notes/4.14.0.txt +0 -68
- data/doc/release_notes/4.15.0.txt +0 -56
- data/doc/release_notes/4.16.0.txt +0 -36
- data/doc/release_notes/4.17.0.txt +0 -38
- data/doc/release_notes/4.18.0.txt +0 -36
- data/doc/release_notes/4.19.0.txt +0 -45
- data/doc/release_notes/4.2.0.txt +0 -129
- data/doc/release_notes/4.20.0.txt +0 -79
- data/doc/release_notes/4.21.0.txt +0 -94
- data/doc/release_notes/4.22.0.txt +0 -72
- data/doc/release_notes/4.23.0.txt +0 -65
- data/doc/release_notes/4.24.0.txt +0 -99
- data/doc/release_notes/4.25.0.txt +0 -181
- data/doc/release_notes/4.26.0.txt +0 -44
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.4.0.txt +0 -92
- data/doc/release_notes/4.5.0.txt +0 -34
- data/doc/release_notes/4.6.0.txt +0 -30
- data/doc/release_notes/4.7.0.txt +0 -103
- data/doc/release_notes/4.8.0.txt +0 -175
- data/doc/release_notes/4.9.0.txt +0 -190
- data/lib/sequel/adapters/cubrid.rb +0 -142
- data/lib/sequel/adapters/do.rb +0 -156
- data/lib/sequel/adapters/do/mysql.rb +0 -64
- data/lib/sequel/adapters/do/postgres.rb +0 -42
- data/lib/sequel/adapters/do/sqlite3.rb +0 -40
- data/lib/sequel/adapters/jdbc/as400.rb +0 -82
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -62
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -34
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -31
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -31
- data/lib/sequel/adapters/odbc/progress.rb +0 -8
- data/lib/sequel/adapters/shared/cubrid.rb +0 -243
- data/lib/sequel/adapters/shared/firebird.rb +0 -245
- data/lib/sequel/adapters/shared/informix.rb +0 -52
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -150
- data/lib/sequel/adapters/shared/progress.rb +0 -38
- data/lib/sequel/adapters/swift.rb +0 -158
- data/lib/sequel/adapters/swift/mysql.rb +0 -47
- data/lib/sequel/adapters/swift/postgres.rb +0 -45
- data/lib/sequel/adapters/swift/sqlite.rb +0 -47
- data/lib/sequel/adapters/utils/pg_types.rb +0 -68
- data/lib/sequel/dataset/mutation.rb +0 -109
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -3
- data/lib/sequel/extensions/filter_having.rb +0 -59
- data/lib/sequel/extensions/hash_aliases.rb +0 -45
- data/lib/sequel/extensions/meta_def.rb +0 -31
- data/lib/sequel/extensions/query_literals.rb +0 -80
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -22
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -118
- data/lib/sequel/extensions/set_overrides.rb +0 -72
- data/lib/sequel/no_core_ext.rb +0 -1
- data/lib/sequel/plugins/association_autoreloading.rb +0 -7
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -7
- data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -78
- data/lib/sequel/plugins/prepared_statements_associations.rb +0 -117
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -59
- data/lib/sequel/plugins/schema.rb +0 -80
- data/lib/sequel/plugins/scissors.rb +0 -33
- data/spec/adapters/db2_spec.rb +0 -160
- data/spec/adapters/firebird_spec.rb +0 -411
- data/spec/adapters/informix_spec.rb +0 -100
- data/spec/adapters/mssql_spec.rb +0 -706
- data/spec/adapters/mysql_spec.rb +0 -1287
- data/spec/adapters/oracle_spec.rb +0 -313
- data/spec/adapters/postgres_spec.rb +0 -3725
- data/spec/adapters/spec_helper.rb +0 -43
- data/spec/adapters/sqlanywhere_spec.rb +0 -170
- data/spec/adapters/sqlite_spec.rb +0 -653
- data/spec/bin_spec.rb +0 -254
- data/spec/core/connection_pool_spec.rb +0 -1016
- data/spec/core/database_spec.rb +0 -2531
- data/spec/core/dataset_spec.rb +0 -5098
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1243
- data/spec/core/mock_adapter_spec.rb +0 -462
- data/spec/core/object_graph_spec.rb +0 -303
- data/spec/core/placeholder_literalizer_spec.rb +0 -163
- data/spec/core/schema_generator_spec.rb +0 -179
- data/spec/core/schema_spec.rb +0 -1659
- data/spec/core/spec_helper.rb +0 -34
- data/spec/core/version_spec.rb +0 -7
- data/spec/core_extensions_spec.rb +0 -699
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -123
- data/spec/extensions/after_initialize_spec.rb +0 -24
- data/spec/extensions/arbitrary_servers_spec.rb +0 -109
- data/spec/extensions/association_dependencies_spec.rb +0 -117
- data/spec/extensions/association_pks_spec.rb +0 -365
- data/spec/extensions/association_proxies_spec.rb +0 -86
- data/spec/extensions/auto_validations_spec.rb +0 -192
- data/spec/extensions/blacklist_security_spec.rb +0 -88
- data/spec/extensions/blank_spec.rb +0 -69
- data/spec/extensions/boolean_readers_spec.rb +0 -93
- data/spec/extensions/caching_spec.rb +0 -270
- data/spec/extensions/class_table_inheritance_spec.rb +0 -420
- data/spec/extensions/column_conflicts_spec.rb +0 -60
- data/spec/extensions/column_select_spec.rb +0 -108
- data/spec/extensions/columns_introspection_spec.rb +0 -91
- data/spec/extensions/composition_spec.rb +0 -242
- data/spec/extensions/connection_validator_spec.rb +0 -120
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -274
- data/spec/extensions/constraint_validations_spec.rb +0 -325
- data/spec/extensions/core_refinements_spec.rb +0 -519
- data/spec/extensions/csv_serializer_spec.rb +0 -173
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -311
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -150
- data/spec/extensions/defaults_setter_spec.rb +0 -101
- data/spec/extensions/delay_add_association_spec.rb +0 -52
- data/spec/extensions/dirty_spec.rb +0 -180
- data/spec/extensions/eager_each_spec.rb +0 -42
- data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
- data/spec/extensions/error_splitter_spec.rb +0 -18
- data/spec/extensions/error_sql_spec.rb +0 -20
- data/spec/extensions/eval_inspect_spec.rb +0 -73
- data/spec/extensions/filter_having_spec.rb +0 -40
- data/spec/extensions/force_encoding_spec.rb +0 -114
- data/spec/extensions/from_block_spec.rb +0 -21
- data/spec/extensions/graph_each_spec.rb +0 -109
- data/spec/extensions/hash_aliases_spec.rb +0 -24
- data/spec/extensions/hook_class_methods_spec.rb +0 -429
- data/spec/extensions/inflector_spec.rb +0 -183
- data/spec/extensions/input_transformer_spec.rb +0 -54
- data/spec/extensions/insert_returning_select_spec.rb +0 -46
- data/spec/extensions/instance_filters_spec.rb +0 -79
- data/spec/extensions/instance_hooks_spec.rb +0 -276
- data/spec/extensions/inverted_subsets_spec.rb +0 -33
- data/spec/extensions/json_serializer_spec.rb +0 -291
- data/spec/extensions/lazy_attributes_spec.rb +0 -170
- data/spec/extensions/list_spec.rb +0 -267
- data/spec/extensions/looser_typecasting_spec.rb +0 -43
- data/spec/extensions/many_through_many_spec.rb +0 -2172
- data/spec/extensions/meta_def_spec.rb +0 -21
- data/spec/extensions/migration_spec.rb +0 -712
- data/spec/extensions/modification_detection_spec.rb +0 -80
- data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
- data/spec/extensions/named_timezones_spec.rb +0 -108
- data/spec/extensions/nested_attributes_spec.rb +0 -697
- data/spec/extensions/null_dataset_spec.rb +0 -85
- data/spec/extensions/optimistic_locking_spec.rb +0 -128
- data/spec/extensions/pagination_spec.rb +0 -118
- data/spec/extensions/pg_array_associations_spec.rb +0 -736
- data/spec/extensions/pg_array_ops_spec.rb +0 -143
- data/spec/extensions/pg_array_spec.rb +0 -395
- data/spec/extensions/pg_enum_spec.rb +0 -92
- data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
- data/spec/extensions/pg_hstore_spec.rb +0 -206
- data/spec/extensions/pg_inet_ops_spec.rb +0 -101
- data/spec/extensions/pg_inet_spec.rb +0 -52
- data/spec/extensions/pg_interval_spec.rb +0 -76
- data/spec/extensions/pg_json_ops_spec.rb +0 -229
- data/spec/extensions/pg_json_spec.rb +0 -218
- data/spec/extensions/pg_loose_count_spec.rb +0 -17
- data/spec/extensions/pg_range_ops_spec.rb +0 -58
- data/spec/extensions/pg_range_spec.rb +0 -404
- data/spec/extensions/pg_row_ops_spec.rb +0 -60
- data/spec/extensions/pg_row_plugin_spec.rb +0 -62
- data/spec/extensions/pg_row_spec.rb +0 -360
- data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
- data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
- data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
- data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
- data/spec/extensions/prepared_statements_spec.rb +0 -103
- data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
- data/spec/extensions/pretty_table_spec.rb +0 -92
- data/spec/extensions/query_literals_spec.rb +0 -183
- data/spec/extensions/query_spec.rb +0 -102
- data/spec/extensions/rcte_tree_spec.rb +0 -392
- data/spec/extensions/round_timestamps_spec.rb +0 -43
- data/spec/extensions/schema_caching_spec.rb +0 -41
- data/spec/extensions/schema_dumper_spec.rb +0 -789
- data/spec/extensions/schema_spec.rb +0 -117
- data/spec/extensions/scissors_spec.rb +0 -26
- data/spec/extensions/select_remove_spec.rb +0 -38
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
- data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
- data/spec/extensions/serialization_spec.rb +0 -362
- data/spec/extensions/server_block_spec.rb +0 -90
- data/spec/extensions/set_overrides_spec.rb +0 -61
- data/spec/extensions/sharding_spec.rb +0 -198
- data/spec/extensions/shared_caching_spec.rb +0 -175
- data/spec/extensions/single_table_inheritance_spec.rb +0 -297
- data/spec/extensions/singular_table_names_spec.rb +0 -22
- data/spec/extensions/skip_create_refresh_spec.rb +0 -17
- data/spec/extensions/spec_helper.rb +0 -71
- data/spec/extensions/split_array_nil_spec.rb +0 -24
- data/spec/extensions/split_values_spec.rb +0 -22
- data/spec/extensions/sql_expr_spec.rb +0 -60
- data/spec/extensions/static_cache_spec.rb +0 -361
- data/spec/extensions/string_date_time_spec.rb +0 -95
- data/spec/extensions/string_stripper_spec.rb +0 -68
- data/spec/extensions/subclasses_spec.rb +0 -66
- data/spec/extensions/table_select_spec.rb +0 -71
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -82
- data/spec/extensions/thread_local_timezones_spec.rb +0 -67
- data/spec/extensions/timestamps_spec.rb +0 -175
- data/spec/extensions/to_dot_spec.rb +0 -154
- data/spec/extensions/touch_spec.rb +0 -203
- data/spec/extensions/tree_spec.rb +0 -274
- data/spec/extensions/typecast_on_load_spec.rb +0 -80
- data/spec/extensions/unlimited_update_spec.rb +0 -20
- data/spec/extensions/update_or_create_spec.rb +0 -87
- data/spec/extensions/update_primary_key_spec.rb +0 -100
- data/spec/extensions/update_refresh_spec.rb +0 -53
- data/spec/extensions/validate_associated_spec.rb +0 -52
- data/spec/extensions/validation_class_methods_spec.rb +0 -1027
- data/spec/extensions/validation_helpers_spec.rb +0 -541
- data/spec/extensions/xml_serializer_spec.rb +0 -207
- data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
- data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
- data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
- data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
- data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
- data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
- data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
- data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
- data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
- data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
- data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
- data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
- data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/reversible_migrations/001_reversible.rb +0 -5
- data/spec/files/reversible_migrations/002_reversible.rb +0 -5
- data/spec/files/reversible_migrations/003_reversible.rb +0 -5
- data/spec/files/reversible_migrations/004_reversible.rb +0 -5
- data/spec/files/reversible_migrations/005_reversible.rb +0 -10
- data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
- data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
- data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
- data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
- data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
- data/spec/guards_helper.rb +0 -55
- data/spec/integration/associations_test.rb +0 -2454
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1808
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -240
- data/spec/integration/model_test.rb +0 -226
- data/spec/integration/plugin_test.rb +0 -2240
- data/spec/integration/prepared_statement_test.rb +0 -467
- data/spec/integration/schema_test.rb +0 -817
- data/spec/integration/spec_helper.rb +0 -48
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -374
- data/spec/integration/type_test.rb +0 -133
- data/spec/model/association_reflection_spec.rb +0 -525
- data/spec/model/associations_spec.rb +0 -4426
- data/spec/model/base_spec.rb +0 -759
- data/spec/model/class_dataset_methods_spec.rb +0 -146
- data/spec/model/dataset_methods_spec.rb +0 -149
- data/spec/model/eager_loading_spec.rb +0 -2137
- data/spec/model/hooks_spec.rb +0 -604
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -982
- data/spec/model/plugins_spec.rb +0 -299
- data/spec/model/record_spec.rb +0 -2147
- data/spec/model/spec_helper.rb +0 -46
- data/spec/model/validations_spec.rb +0 -193
- data/spec/sequel_coverage.rb +0 -15
- data/spec/spec_config.rb +0 -10
data/lib/sequel/model/base.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
1
3
|
module Sequel
|
|
2
4
|
class Model
|
|
3
5
|
extend Enumerable
|
|
@@ -5,18 +7,33 @@ module Sequel
|
|
|
5
7
|
|
|
6
8
|
# Class methods for Sequel::Model that implement basic model functionality.
|
|
7
9
|
#
|
|
8
|
-
# * All of the
|
|
9
|
-
# the
|
|
10
|
+
# * All of the following methods have class methods created that send the method
|
|
11
|
+
# to the model's dataset: all, as_hash, avg, count, cross_join, distinct, each,
|
|
12
|
+
# each_server, empty?, except, exclude, exclude_having, fetch_rows,
|
|
13
|
+
# filter, first, first!, for_update, from, from_self, full_join, full_outer_join,
|
|
14
|
+
# get, graph, grep, group, group_and_count, group_append, group_by, having, import,
|
|
15
|
+
# inner_join, insert, intersect, invert, join, join_table, last, left_join,
|
|
16
|
+
# left_outer_join, limit, lock_style, map, max, min, multi_insert, naked, natural_full_join,
|
|
17
|
+
# natural_join, natural_left_join, natural_right_join, offset, order, order_append, order_by,
|
|
18
|
+
# order_more, order_prepend, paged_each, qualify, reverse, reverse_order, right_join,
|
|
19
|
+
# right_outer_join, select, select_all, select_append, select_group, select_hash,
|
|
20
|
+
# select_hash_groups, select_map, select_more, select_order_map, server,
|
|
21
|
+
# single_record, single_record!, single_value, single_value!, sum, to_hash, to_hash_groups,
|
|
22
|
+
# truncate, unfiltered, ungraphed, ungrouped, union, unlimited, unordered, where, where_all,
|
|
23
|
+
# where_each, where_single_value, with, with_recursive, with_sql
|
|
10
24
|
module ClassMethods
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
|
|
25
|
+
# Whether to cache the anonymous models created by Sequel::Model(), true by default. This is
|
|
26
|
+
# required for reloading them correctly (avoiding the superclass mismatch).
|
|
27
|
+
attr_accessor :cache_anonymous_models
|
|
14
28
|
|
|
15
29
|
# Array of modules that extend this model's dataset. Stored
|
|
16
30
|
# so that if the model's dataset is changed, it will be extended
|
|
17
31
|
# with all of these modules.
|
|
18
32
|
attr_reader :dataset_method_modules
|
|
19
33
|
|
|
34
|
+
# The Module subclass to use for dataset_module blocks.
|
|
35
|
+
attr_reader :dataset_module_class
|
|
36
|
+
|
|
20
37
|
# The default options to use for Model#set_fields. These are merged with
|
|
21
38
|
# the options given to set_fields.
|
|
22
39
|
attr_accessor :default_set_fields_options
|
|
@@ -25,6 +42,10 @@ module Sequel
|
|
|
25
42
|
# model instances, or nil if the optimization should not be used. For internal use only.
|
|
26
43
|
attr_reader :fast_instance_delete_sql
|
|
27
44
|
|
|
45
|
+
# SQL string fragment used for faster lookups by primary key, or nil if the optimization
|
|
46
|
+
# should not be used. For internal use only.
|
|
47
|
+
attr_reader :fast_pk_lookup_sql
|
|
48
|
+
|
|
28
49
|
# The dataset that instance datasets (#this) are based on. Generally a naked version of
|
|
29
50
|
# the model's dataset limited to one row. For internal use only.
|
|
30
51
|
attr_reader :instance_dataset
|
|
@@ -46,11 +67,8 @@ module Sequel
|
|
|
46
67
|
attr_accessor :raise_on_save_failure
|
|
47
68
|
|
|
48
69
|
# Whether to raise an error when unable to typecast data for a column
|
|
49
|
-
# (default:
|
|
50
|
-
#
|
|
51
|
-
# web applications). You can use the validates_schema_types validation
|
|
52
|
-
# (from the validation_helpers plugin) in connection with this setting to
|
|
53
|
-
# check for typecast failures during validation.
|
|
70
|
+
# (default: false). This should be set to true if you want to have model
|
|
71
|
+
# setter methods raise errors if the argument cannot be typecast properly.
|
|
54
72
|
attr_accessor :raise_on_typecast_failure
|
|
55
73
|
|
|
56
74
|
# Whether to raise an error if an UPDATE or DELETE query related to
|
|
@@ -58,6 +76,12 @@ module Sequel
|
|
|
58
76
|
# Sequel will not check the number of rows modified (default: true).
|
|
59
77
|
attr_accessor :require_modification
|
|
60
78
|
|
|
79
|
+
# If true (the default), requires that all models have valid tables,
|
|
80
|
+
# raising exceptions if creating a model without a valid table backing it.
|
|
81
|
+
# Setting this to false will allow the creation of model classes where the
|
|
82
|
+
# underlying table doesn't exist.
|
|
83
|
+
attr_accessor :require_valid_table
|
|
84
|
+
|
|
61
85
|
# Should be the literal primary key column name if this Model's table has a simple primary key, or
|
|
62
86
|
# nil if the model has a compound primary key or no primary key.
|
|
63
87
|
attr_reader :simple_pk
|
|
@@ -66,7 +90,7 @@ module Sequel
|
|
|
66
90
|
# or nil otherwise. This and simple_pk are used for an optimization in Model.[].
|
|
67
91
|
attr_reader :simple_table
|
|
68
92
|
|
|
69
|
-
# Whether new
|
|
93
|
+
# Whether mass assigning via .create/.new/#set/#update should raise an error
|
|
70
94
|
# if an invalid key is used. A key is invalid if no setter method exists
|
|
71
95
|
# for that key or the access to the setter method is restricted (e.g. due to it
|
|
72
96
|
# being a primary key field). If set to false, silently skip
|
|
@@ -85,15 +109,95 @@ module Sequel
|
|
|
85
109
|
# database to typecast the value correctly.
|
|
86
110
|
attr_accessor :typecast_on_assignment
|
|
87
111
|
|
|
88
|
-
# Whether to enable the after_commit and after_rollback hooks when saving/destroying
|
|
89
|
-
# instances. On by default, can be turned off for performance reasons or when using
|
|
90
|
-
# prepared transactions (which aren't compatible with after commit/rollback).
|
|
91
|
-
attr_accessor :use_after_commit_rollback
|
|
92
|
-
|
|
93
112
|
# Whether to use a transaction by default when saving/deleting records (default: true).
|
|
94
113
|
# If you are sending database queries in before_* or after_* hooks, you shouldn't change
|
|
95
114
|
# the default setting without a good reason.
|
|
96
115
|
attr_accessor :use_transactions
|
|
116
|
+
|
|
117
|
+
# Define a Model method on the given module that calls the Model
|
|
118
|
+
# method on the receiver. This is how the Sequel::Model() method is
|
|
119
|
+
# defined, and allows you to define Model() methods on other modules,
|
|
120
|
+
# making it easier to have custom model settings for all models under
|
|
121
|
+
# a namespace. Example:
|
|
122
|
+
#
|
|
123
|
+
# module Foo
|
|
124
|
+
# Model = Class.new(Sequel::Model)
|
|
125
|
+
# Model.def_Model(self)
|
|
126
|
+
# DB = Model.db = Sequel.connect(ENV['FOO_DATABASE_URL'])
|
|
127
|
+
# Model.plugin :prepared_statements
|
|
128
|
+
#
|
|
129
|
+
# class Bar < Model
|
|
130
|
+
# # Uses Foo::DB[:bars]
|
|
131
|
+
# end
|
|
132
|
+
#
|
|
133
|
+
# class Baz < Model(:my_baz)
|
|
134
|
+
# # Uses Foo::DB[:my_baz]
|
|
135
|
+
# end
|
|
136
|
+
# end
|
|
137
|
+
def def_Model(mod)
|
|
138
|
+
model = self
|
|
139
|
+
mod.define_singleton_method(:Model) do |source|
|
|
140
|
+
model.Model(source)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Lets you create a Model subclass with its dataset already set.
|
|
145
|
+
# +source+ should be an instance of one of the following classes:
|
|
146
|
+
#
|
|
147
|
+
# Database :: Sets the database for this model to +source+.
|
|
148
|
+
# Generally only useful when subclassing directly
|
|
149
|
+
# from the returned class, where the name of the
|
|
150
|
+
# subclass sets the table name (which is combined
|
|
151
|
+
# with the +Database+ in +source+ to create the
|
|
152
|
+
# dataset to use)
|
|
153
|
+
# Dataset :: Sets the dataset for this model to +source+.
|
|
154
|
+
# other :: Sets the table name for this model to +source+. The
|
|
155
|
+
# class will use the default database for model
|
|
156
|
+
# classes in order to create the dataset.
|
|
157
|
+
#
|
|
158
|
+
# The purpose of this method is to set the dataset/database automatically
|
|
159
|
+
# for a model class, if the table name doesn't match the default table
|
|
160
|
+
# name that Sequel would use.
|
|
161
|
+
#
|
|
162
|
+
# When creating subclasses of Sequel::Model itself, this method is usually
|
|
163
|
+
# called on Sequel itself, using <tt>Sequel::Model(:something)</tt>.
|
|
164
|
+
#
|
|
165
|
+
# # Using a symbol
|
|
166
|
+
# class Comment < Sequel::Model(:something)
|
|
167
|
+
# table_name # => :something
|
|
168
|
+
# end
|
|
169
|
+
#
|
|
170
|
+
# # Using a dataset
|
|
171
|
+
# class Comment < Sequel::Model(DB1[:something])
|
|
172
|
+
# dataset # => DB1[:something]
|
|
173
|
+
# end
|
|
174
|
+
#
|
|
175
|
+
# # Using a database
|
|
176
|
+
# class Comment < Sequel::Model(DB1)
|
|
177
|
+
# dataset # => DB1[:comments]
|
|
178
|
+
# end
|
|
179
|
+
def Model(source)
|
|
180
|
+
if cache_anonymous_models
|
|
181
|
+
cache = Sequel.synchronize{@Model_cache ||= {}}
|
|
182
|
+
if klass = Sequel.synchronize{cache[source]}
|
|
183
|
+
return klass
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
klass = Class.new(self)
|
|
188
|
+
|
|
189
|
+
if source.is_a?(::Sequel::Database)
|
|
190
|
+
klass.db = source
|
|
191
|
+
else
|
|
192
|
+
klass.set_dataset(source)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
if cache_anonymous_models
|
|
196
|
+
Sequel.synchronize{cache[source] = klass}
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
klass
|
|
200
|
+
end
|
|
97
201
|
|
|
98
202
|
# Returns the first record from the database matching the conditions.
|
|
99
203
|
# If a hash is given, it is used as the conditions. If another
|
|
@@ -103,11 +207,11 @@ module Sequel
|
|
|
103
207
|
# Artist[1] # SELECT * FROM artists WHERE id = 1
|
|
104
208
|
# # => #<Artist {:id=>1, ...}>
|
|
105
209
|
#
|
|
106
|
-
# Artist[:
|
|
210
|
+
# Artist[name: 'Bob'] # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
|
107
211
|
# # => #<Artist {:name=>'Bob', ...}>
|
|
108
212
|
def [](*args)
|
|
109
213
|
args = args.first if args.size <= 1
|
|
110
|
-
args.is_a?(Hash) ?
|
|
214
|
+
args.is_a?(Hash) ? first(args) : (primary_key_lookup(args) unless args.nil?)
|
|
111
215
|
end
|
|
112
216
|
|
|
113
217
|
# Initializes a model instance as an existing record. This constructor is
|
|
@@ -122,7 +226,7 @@ module Sequel
|
|
|
122
226
|
|
|
123
227
|
# Clear the setter_methods cache
|
|
124
228
|
def clear_setter_methods_cache
|
|
125
|
-
@setter_methods = nil
|
|
229
|
+
@setter_methods = nil unless frozen?
|
|
126
230
|
end
|
|
127
231
|
|
|
128
232
|
# Returns the columns in the result set in their original order.
|
|
@@ -133,18 +237,20 @@ module Sequel
|
|
|
133
237
|
# Artist.columns
|
|
134
238
|
# # => [:id, :name]
|
|
135
239
|
def columns
|
|
136
|
-
@columns
|
|
240
|
+
return @columns if @columns
|
|
241
|
+
return nil if frozen?
|
|
242
|
+
set_columns(dataset.naked.columns)
|
|
137
243
|
end
|
|
138
244
|
|
|
139
245
|
# Creates instance using new with the given values and block, and saves it.
|
|
140
246
|
#
|
|
141
|
-
# Artist.create(:
|
|
247
|
+
# Artist.create(name: 'Bob')
|
|
142
248
|
# # INSERT INTO artists (name) VALUES ('Bob')
|
|
143
249
|
#
|
|
144
250
|
# Artist.create do |a|
|
|
145
251
|
# a.name = 'Jim'
|
|
146
252
|
# end # INSERT INTO artists (name) VALUES ('Jim')
|
|
147
|
-
def create(values =
|
|
253
|
+
def create(values = OPTS, &block)
|
|
148
254
|
new(values, &block).save
|
|
149
255
|
end
|
|
150
256
|
|
|
@@ -167,49 +273,70 @@ module Sequel
|
|
|
167
273
|
# a plugin with the methods defined in DatasetMethods.
|
|
168
274
|
# This is the recommended way to add methods to model datasets.
|
|
169
275
|
#
|
|
170
|
-
# If an argument, it should be a module, and is used to extend
|
|
276
|
+
# If given an argument, it should be a module, and is used to extend
|
|
171
277
|
# the underlying dataset. Otherwise an anonymous module is created, and
|
|
172
278
|
# if a block is given, it is module_evaled, allowing you do define
|
|
173
279
|
# dataset methods directly using the standard ruby def syntax.
|
|
174
280
|
# Returns the module given or the anonymous module created.
|
|
175
281
|
#
|
|
176
282
|
# # Usage with existing module
|
|
177
|
-
#
|
|
283
|
+
# Album.dataset_module Sequel::ColumnsIntrospection
|
|
178
284
|
#
|
|
179
285
|
# # Usage with anonymous module
|
|
180
|
-
#
|
|
286
|
+
# Album.dataset_module do
|
|
181
287
|
# def foo
|
|
182
288
|
# :bar
|
|
183
289
|
# end
|
|
184
290
|
# end
|
|
185
|
-
#
|
|
291
|
+
# Album.dataset.foo
|
|
186
292
|
# # => :bar
|
|
187
|
-
#
|
|
293
|
+
# Album.foo
|
|
188
294
|
# # => :bar
|
|
189
295
|
#
|
|
190
296
|
# Any anonymous modules created are actually instances of Sequel::Model::DatasetModule
|
|
191
|
-
# (a Module subclass), which allows you to call the subset method on them
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
297
|
+
# (a Module subclass), which allows you to call the subset method on them, which
|
|
298
|
+
# defines a dataset method that adds a filter. There are also a number of other
|
|
299
|
+
# methods with the same names as the dataset methods, which can use to define
|
|
300
|
+
# named dataset methods:
|
|
301
|
+
#
|
|
302
|
+
# Album.dataset_module do
|
|
303
|
+
# where(:released, Sequel[:release_date] <= Sequel::CURRENT_DATE)
|
|
304
|
+
# order :by_release_date, :release_date
|
|
305
|
+
# select :for_select_options, :id, :name, :release_date
|
|
195
306
|
# end
|
|
307
|
+
# Album.released.sql
|
|
308
|
+
# # => "SELECT * FROM artists WHERE (release_date <= CURRENT_DATE)"
|
|
309
|
+
# Album.by_release_date.sql
|
|
310
|
+
# # => "SELECT * FROM artists ORDER BY release_date"
|
|
311
|
+
# Album.for_select_options.sql
|
|
312
|
+
# # => "SELECT id, name, release_date FROM artists"
|
|
313
|
+
# Album.released.by_release_date.for_select_options.sql
|
|
314
|
+
# # => "SELECT id, name, release_date FROM artists WHERE (release_date <= CURRENT_DATE) ORDER BY release_date"
|
|
315
|
+
#
|
|
316
|
+
# The following methods are supported: distinct, eager, exclude, exclude_having, grep, group, group_and_count,
|
|
317
|
+
# group_append, having, limit, offset, order, order_append, order_prepend, select, select_all,
|
|
318
|
+
# select_append, select_group, where, and server.
|
|
319
|
+
#
|
|
320
|
+
# The advantage of using these DatasetModule methods to define your dataset
|
|
321
|
+
# methods is that they can take advantage of dataset caching to improve
|
|
322
|
+
# performance.
|
|
196
323
|
#
|
|
197
324
|
# Any public methods in the dataset module will have class methods created that
|
|
198
325
|
# call the method on the dataset, assuming that the class method is not already
|
|
199
326
|
# defined.
|
|
200
|
-
def dataset_module(mod = nil)
|
|
327
|
+
def dataset_module(mod = nil, &block)
|
|
201
328
|
if mod
|
|
202
|
-
raise Error, "can't provide both argument and block to Model.dataset_module" if
|
|
329
|
+
raise Error, "can't provide both argument and block to Model.dataset_module" if block
|
|
203
330
|
dataset_extend(mod)
|
|
204
331
|
mod
|
|
205
332
|
else
|
|
206
|
-
@dataset_module ||=
|
|
207
|
-
@dataset_module.module_eval(&
|
|
333
|
+
@dataset_module ||= dataset_module_class.new(self)
|
|
334
|
+
@dataset_module.module_eval(&block) if block
|
|
208
335
|
dataset_extend(@dataset_module)
|
|
209
336
|
@dataset_module
|
|
210
337
|
end
|
|
211
338
|
end
|
|
212
|
-
|
|
339
|
+
|
|
213
340
|
# Returns the database associated with the Model class.
|
|
214
341
|
# If this model doesn't have a database associated with it,
|
|
215
342
|
# assumes the superclass's database, or the first object in
|
|
@@ -217,7 +344,7 @@ module Sequel
|
|
|
217
344
|
# been created, raises an error.
|
|
218
345
|
#
|
|
219
346
|
# Artist.db.transaction do # BEGIN
|
|
220
|
-
# Artist.create(:
|
|
347
|
+
# Artist.create(name: 'Bob')
|
|
221
348
|
# # INSERT INTO artists (name) VALUES ('Bob')
|
|
222
349
|
# end # COMMIT
|
|
223
350
|
def db
|
|
@@ -227,23 +354,23 @@ module Sequel
|
|
|
227
354
|
@db
|
|
228
355
|
end
|
|
229
356
|
|
|
230
|
-
# Sets the database associated with the Model class.
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
# Sequel::Model to set the default database to be used
|
|
235
|
-
# by subclasses, or to override the database used for specific
|
|
236
|
-
# models:
|
|
357
|
+
# Sets the database associated with the Model class.
|
|
358
|
+
# Should only be used if the Model class currently does not
|
|
359
|
+
# have a dataset defined.
|
|
360
|
+
#
|
|
361
|
+
# This can be used directly on Sequel::Model to set the default database to be used
|
|
362
|
+
# by subclasses, or to override the database used for specific models:
|
|
237
363
|
#
|
|
238
364
|
# Sequel::Model.db = DB1
|
|
365
|
+
# Artist = Class.new(Sequel::Model)
|
|
239
366
|
# Artist.db = DB2
|
|
240
367
|
#
|
|
241
368
|
# Note that you should not use this to change the model's database
|
|
242
369
|
# at runtime. If you have that need, you should look into Sequel's
|
|
243
|
-
# sharding support.
|
|
370
|
+
# sharding support, or consider using separate model classes per Database.
|
|
244
371
|
def db=(db)
|
|
372
|
+
raise Error, "Cannot use Sequel::Model.db= on model with existing dataset. Use Sequel::Model.dataset= instead." if @dataset
|
|
245
373
|
@db = db
|
|
246
|
-
set_dataset(db.dataset.clone(@dataset.opts)) if @dataset
|
|
247
374
|
end
|
|
248
375
|
|
|
249
376
|
# Returns the cached schema information if available or gets it
|
|
@@ -255,7 +382,9 @@ module Sequel
|
|
|
255
382
|
# # {:id=>{:type=>:integer, :primary_key=>true, ...},
|
|
256
383
|
# # :name=>{:type=>:string, :primary_key=>false, ...}}
|
|
257
384
|
def db_schema
|
|
258
|
-
@db_schema
|
|
385
|
+
return @db_schema if @db_schema
|
|
386
|
+
return nil if frozen?
|
|
387
|
+
@db_schema = get_db_schema
|
|
259
388
|
end
|
|
260
389
|
|
|
261
390
|
# Create a column alias, where the column methods have one name, but the underlying storage uses a
|
|
@@ -268,52 +397,16 @@ module Sequel
|
|
|
268
397
|
end
|
|
269
398
|
end
|
|
270
399
|
|
|
271
|
-
# If a block is given, define a method on the dataset (if the model currently has an dataset) with the given argument name using
|
|
272
|
-
# the given block. Also define a class method on the model that calls the
|
|
273
|
-
# dataset method. Stores the method name and block so that it can be reapplied if the model's
|
|
274
|
-
# dataset changes.
|
|
275
|
-
#
|
|
276
|
-
# If a block is not given, just define a class method on the model for each argument
|
|
277
|
-
# that calls the dataset method of the same argument name.
|
|
278
|
-
#
|
|
279
|
-
# It is recommended that you define methods inside a block passed to #dataset_module
|
|
280
|
-
# instead of using this method, as #dataset_module allows you to use normal
|
|
281
|
-
# ruby def syntax.
|
|
282
|
-
#
|
|
283
|
-
# # Add new dataset method and class method that calls it
|
|
284
|
-
# Artist.def_dataset_method(:by_name){order(:name)}
|
|
285
|
-
# Artist.filter(:name.like('A%')).by_name
|
|
286
|
-
# Artist.by_name.filter(:name.like('A%'))
|
|
287
|
-
#
|
|
288
|
-
# # Just add a class method that calls an existing dataset method
|
|
289
|
-
# Artist.def_dataset_method(:server!)
|
|
290
|
-
# Artist.server!(:server1)
|
|
291
|
-
def def_dataset_method(*args, &block)
|
|
292
|
-
raise(Error, "No arguments given") if args.empty?
|
|
293
|
-
|
|
294
|
-
if block
|
|
295
|
-
raise(Error, "Defining a dataset method using a block requires only one argument") if args.length > 1
|
|
296
|
-
dataset_module{define_method(args.first, &block)}
|
|
297
|
-
else
|
|
298
|
-
args.each{|arg| def_model_dataset_method(arg)}
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
400
|
# Finds a single record according to the supplied filter.
|
|
303
401
|
# You are encouraged to use Model.[] or Model.first instead of this method.
|
|
304
402
|
#
|
|
305
|
-
# Artist.find(:
|
|
403
|
+
# Artist.find(name: 'Bob')
|
|
306
404
|
# # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
|
307
405
|
#
|
|
308
406
|
# Artist.find{name > 'M'}
|
|
309
407
|
# # SELECT * FROM artists WHERE (name > 'M') LIMIT 1
|
|
310
408
|
def find(*args, &block)
|
|
311
|
-
|
|
312
|
-
# Use optimized finder
|
|
313
|
-
first_where(args.first)
|
|
314
|
-
else
|
|
315
|
-
filter(*args, &block).first
|
|
316
|
-
end
|
|
409
|
+
first(*args, &block)
|
|
317
410
|
end
|
|
318
411
|
|
|
319
412
|
# Like +find+ but invokes create with given conditions when record does not
|
|
@@ -321,154 +414,43 @@ module Sequel
|
|
|
321
414
|
# to +find+, but instead is passed to +create+ only if +find+ does not
|
|
322
415
|
# return an object.
|
|
323
416
|
#
|
|
324
|
-
# Artist.find_or_create(:
|
|
417
|
+
# Artist.find_or_create(name: 'Bob')
|
|
325
418
|
# # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
|
326
419
|
# # INSERT INTO artists (name) VALUES ('Bob')
|
|
327
420
|
#
|
|
328
|
-
# Artist.find_or_create(:
|
|
421
|
+
# Artist.find_or_create(name: 'Jim'){|a| a.hometown = 'Sactown'}
|
|
329
422
|
# # SELECT * FROM artists WHERE (name = 'Jim') LIMIT 1
|
|
330
423
|
# # INSERT INTO artists (name, hometown) VALUES ('Jim', 'Sactown')
|
|
331
424
|
def find_or_create(cond, &block)
|
|
332
425
|
find(cond) || create(cond, &block)
|
|
333
426
|
end
|
|
334
|
-
|
|
335
427
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
# end
|
|
347
|
-
#
|
|
348
|
-
# Artist.finder :by_name
|
|
349
|
-
#
|
|
350
|
-
# This creates an optimized first_by_name method, which you can call normally:
|
|
351
|
-
#
|
|
352
|
-
# Artist.first_by_name("Joe")
|
|
353
|
-
#
|
|
354
|
-
# The alternative way to use this to pass your own block:
|
|
355
|
-
#
|
|
356
|
-
# Artist.finder(:name=>:first_by_name){|pl, ds| ds.where(:name=>pl.arg).limit(1)}
|
|
357
|
-
#
|
|
358
|
-
# Note that if you pass your own block, you are responsible for manually setting
|
|
359
|
-
# limits if necessary (as shown above).
|
|
360
|
-
#
|
|
361
|
-
# Options:
|
|
362
|
-
# :arity :: When using a symbol method name, this specifies the arity of the method.
|
|
363
|
-
# This should be used if if the method accepts an arbitrary number of arguments,
|
|
364
|
-
# or the method has default argument values. Note that if the method is defined
|
|
365
|
-
# as a dataset method, the class method Sequel creates accepts an arbitrary number
|
|
366
|
-
# of arguments, so you should use this option in that case. If you want to handle
|
|
367
|
-
# multiple possible arities, you need to call the finder method multiple times with
|
|
368
|
-
# unique :arity and :name methods each time.
|
|
369
|
-
# :name :: The name of the method to create. This must be given if you pass a block.
|
|
370
|
-
# If you use a symbol, this defaults to the symbol prefixed by the type.
|
|
371
|
-
# :mod :: The module in which to create the finder method. Defaults to the singleton
|
|
372
|
-
# class of the model.
|
|
373
|
-
# :type :: The type of query to run. Can be :first, :each, :all, or :get, defaults to
|
|
374
|
-
# :first.
|
|
375
|
-
#
|
|
376
|
-
# Caveats:
|
|
377
|
-
#
|
|
378
|
-
# This doesn't handle all possible cases. For example, if you have a method such as:
|
|
379
|
-
#
|
|
380
|
-
# def Artist.by_name(name)
|
|
381
|
-
# name ? where(:name=>name) : exclude(:name=>nil)
|
|
382
|
-
# end
|
|
383
|
-
#
|
|
384
|
-
# Then calling a finder without an argument will not work as you expect.
|
|
385
|
-
#
|
|
386
|
-
# Artist.finder :by_name
|
|
387
|
-
# Artist.by_name(nil).first
|
|
388
|
-
# # WHERE (name IS NOT NULL)
|
|
389
|
-
# Artist.first_by_name(nil)
|
|
390
|
-
# # WHERE (name IS NULL)
|
|
391
|
-
#
|
|
392
|
-
# See Dataset::PlaceholderLiteralizer for additional caveats.
|
|
393
|
-
def finder(meth=OPTS, opts=OPTS, &block)
|
|
394
|
-
if block
|
|
395
|
-
raise Error, "cannot pass both a method name argument and a block of Model.finder" unless meth.is_a?(Hash)
|
|
396
|
-
raise Error, "cannot pass two option hashes to Model.finder" unless opts.equal?(OPTS)
|
|
397
|
-
opts = meth
|
|
398
|
-
raise Error, "must provide method name via :name option when passing block to Model.finder" unless meth_name = opts[:name]
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
type = opts.fetch(:type, :first)
|
|
402
|
-
unless prepare = opts[:prepare]
|
|
403
|
-
raise Error, ":type option to Model.finder must be :first, :all, :each, or :get" unless FINDER_TYPES.include?(type)
|
|
404
|
-
end
|
|
405
|
-
limit1 = type == :first || type == :get
|
|
406
|
-
meth_name ||= opts[:name] || :"#{type}_#{meth}"
|
|
407
|
-
|
|
408
|
-
argn = lambda do |model|
|
|
409
|
-
if arity = opts[:arity]
|
|
410
|
-
arity
|
|
411
|
-
else
|
|
412
|
-
method = block || model.method(meth)
|
|
413
|
-
(method.arity < 0 ? method.arity.abs - 1 : method.arity)
|
|
414
|
-
end
|
|
415
|
-
end
|
|
416
|
-
|
|
417
|
-
loader_proc = if prepare
|
|
418
|
-
proc do |model|
|
|
419
|
-
args = prepare_method_args('$a', argn.call(model))
|
|
420
|
-
ds = if block
|
|
421
|
-
model.instance_exec(*args, &block)
|
|
422
|
-
else
|
|
423
|
-
model.send(meth, *args)
|
|
424
|
-
end
|
|
425
|
-
ds = ds.limit(1) if limit1
|
|
426
|
-
model_name = model.name
|
|
427
|
-
if model_name.to_s.empty?
|
|
428
|
-
model_name = model.object_id
|
|
429
|
-
else
|
|
430
|
-
model_name = model_name.gsub(/\W/, '_')
|
|
431
|
-
end
|
|
432
|
-
ds.prepare(type, :"#{model_name}_#{meth_name}")
|
|
433
|
-
end
|
|
428
|
+
# Freeze a model class, disallowing any further changes to it.
|
|
429
|
+
def freeze
|
|
430
|
+
return self if frozen?
|
|
431
|
+
dataset_module.freeze
|
|
432
|
+
overridable_methods_module.freeze
|
|
433
|
+
|
|
434
|
+
if @dataset
|
|
435
|
+
db_schema.freeze.each_value(&:freeze)
|
|
436
|
+
columns.freeze
|
|
437
|
+
setter_methods.freeze
|
|
434
438
|
else
|
|
435
|
-
|
|
436
|
-
n = argn.call(model)
|
|
437
|
-
block ||= lambda do |pl, model2|
|
|
438
|
-
args = (0...n).map{pl.arg}
|
|
439
|
-
ds = model2.send(meth, *args)
|
|
440
|
-
ds = ds.limit(1) if limit1
|
|
441
|
-
ds
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
Sequel::Dataset::PlaceholderLiteralizer.loader(model, &block)
|
|
445
|
-
end
|
|
439
|
+
@setter_methods = [].freeze
|
|
446
440
|
end
|
|
447
441
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
def_prepare_method(mod, meth_name)
|
|
452
|
-
else
|
|
453
|
-
def_finder_method(mod, meth_name, type)
|
|
454
|
-
end
|
|
455
|
-
end
|
|
442
|
+
@dataset_method_modules.freeze
|
|
443
|
+
@default_set_fields_options.freeze
|
|
444
|
+
@plugins.freeze
|
|
456
445
|
|
|
457
|
-
|
|
458
|
-
# optimized handling of the single argument case.
|
|
459
|
-
def first(*args, &block)
|
|
460
|
-
if args.length == 1 && !block && !args.first.is_a?(Integer)
|
|
461
|
-
# Use optimized finder
|
|
462
|
-
first_where(args.first)
|
|
463
|
-
else
|
|
464
|
-
dataset.first(*args, &block)
|
|
465
|
-
end
|
|
446
|
+
super
|
|
466
447
|
end
|
|
467
448
|
|
|
468
|
-
#
|
|
469
|
-
#
|
|
470
|
-
|
|
471
|
-
|
|
449
|
+
# Whether the model has a dataset. True for most model classes,
|
|
450
|
+
# but can be false if the model class is an abstract model class
|
|
451
|
+
# designed for subclassing, such as Sequel::Model itself.
|
|
452
|
+
def has_dataset?
|
|
453
|
+
!@dataset.nil?
|
|
472
454
|
end
|
|
473
455
|
|
|
474
456
|
# Clear the setter_methods cache when a module is included, as it
|
|
@@ -478,47 +460,6 @@ module Sequel
|
|
|
478
460
|
super
|
|
479
461
|
end
|
|
480
462
|
|
|
481
|
-
# If possible, set the dataset for the model subclass as soon as it
|
|
482
|
-
# is created. Also, make sure the inherited class instance variables
|
|
483
|
-
# are copied into the subclass.
|
|
484
|
-
#
|
|
485
|
-
# Sequel queries the database to get schema information as soon as
|
|
486
|
-
# a model class is created:
|
|
487
|
-
#
|
|
488
|
-
# class Artist < Sequel::Model # Causes schema query
|
|
489
|
-
# end
|
|
490
|
-
def inherited(subclass)
|
|
491
|
-
super
|
|
492
|
-
ivs = subclass.instance_variables.collect(&:to_s)
|
|
493
|
-
inherited_instance_variables.each do |iv, dup|
|
|
494
|
-
next if ivs.include?(iv.to_s)
|
|
495
|
-
if (sup_class_value = instance_variable_get(iv)) && dup
|
|
496
|
-
sup_class_value = case dup
|
|
497
|
-
when :dup
|
|
498
|
-
sup_class_value.dup
|
|
499
|
-
when :hash_dup
|
|
500
|
-
h = {}
|
|
501
|
-
sup_class_value.each{|k,v| h[k] = v.dup}
|
|
502
|
-
h
|
|
503
|
-
when Proc
|
|
504
|
-
dup.call(sup_class_value)
|
|
505
|
-
else
|
|
506
|
-
raise Error, "bad inherited instance variable type: #{dup.inspect}"
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
subclass.instance_variable_set(iv, sup_class_value)
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
unless ivs.include?("@dataset")
|
|
513
|
-
if @dataset && self != Model
|
|
514
|
-
subclass.set_dataset(@dataset.clone, :inherited=>true) rescue nil
|
|
515
|
-
elsif (n = subclass.name) && !n.to_s.empty?
|
|
516
|
-
db
|
|
517
|
-
subclass.set_dataset(subclass.implicit_table_name) rescue nil
|
|
518
|
-
end
|
|
519
|
-
end
|
|
520
|
-
end
|
|
521
|
-
|
|
522
463
|
# Returns the implicit table name for the model class, which is the demodulized,
|
|
523
464
|
# underscored, pluralized name of the class.
|
|
524
465
|
#
|
|
@@ -528,17 +469,11 @@ module Sequel
|
|
|
528
469
|
pluralize(underscore(demodulize(name))).to_sym
|
|
529
470
|
end
|
|
530
471
|
|
|
531
|
-
# Calls #call with the values hash.
|
|
472
|
+
# Calls #call with the values hash.
|
|
532
473
|
def load(values)
|
|
533
474
|
call(values)
|
|
534
475
|
end
|
|
535
476
|
|
|
536
|
-
# Clear the setter_methods cache when a setter method is added
|
|
537
|
-
def method_added(meth)
|
|
538
|
-
clear_setter_methods_cache if meth.to_s =~ SETTER_METHOD_REGEXP
|
|
539
|
-
super
|
|
540
|
-
end
|
|
541
|
-
|
|
542
477
|
# Mark the model as not having a primary key. Not having a primary key
|
|
543
478
|
# can cause issues, among which is that you won't be able to update records.
|
|
544
479
|
#
|
|
@@ -552,22 +487,28 @@ module Sequel
|
|
|
552
487
|
|
|
553
488
|
# Loads a plugin for use with the model class, passing optional arguments
|
|
554
489
|
# to the plugin. If the plugin is a module, load it directly. Otherwise,
|
|
555
|
-
# require the plugin from
|
|
556
|
-
#
|
|
557
|
-
# the camelized plugin name under Sequel::Plugins.
|
|
490
|
+
# require the plugin from sequel/plugins/#{plugin} and then attempt to load
|
|
491
|
+
# the module using a the camelized plugin name under Sequel::Plugins.
|
|
558
492
|
def plugin(plugin, *args, &block)
|
|
559
493
|
m = plugin.is_a?(Module) ? plugin : plugin_module(plugin)
|
|
494
|
+
|
|
495
|
+
if !m.respond_to?(:apply) && !m.respond_to?(:configure) && (!args.empty? || block)
|
|
496
|
+
Deprecation.deprecate("Plugin #{plugin} accepts no arguments or block, and passing arguments/block to it", "Remove arguments and block when loading the plugin")
|
|
497
|
+
end
|
|
498
|
+
|
|
560
499
|
unless @plugins.include?(m)
|
|
561
500
|
@plugins << m
|
|
562
501
|
m.apply(self, *args, &block) if m.respond_to?(:apply)
|
|
563
|
-
extend(m::ClassMethods) if
|
|
564
|
-
include(m::InstanceMethods) if
|
|
565
|
-
if
|
|
502
|
+
extend(m::ClassMethods) if m.const_defined?(:ClassMethods, false)
|
|
503
|
+
include(m::InstanceMethods) if m.const_defined?(:InstanceMethods, false)
|
|
504
|
+
if m.const_defined?(:DatasetMethods, false)
|
|
566
505
|
dataset_extend(m::DatasetMethods, :create_class_methods=>false)
|
|
567
506
|
end
|
|
568
507
|
end
|
|
508
|
+
|
|
569
509
|
m.configure(self, *args, &block) if m.respond_to?(:configure)
|
|
570
510
|
end
|
|
511
|
+
ruby2_keywords(:plugin) if respond_to?(:ruby2_keywords, true)
|
|
571
512
|
|
|
572
513
|
# Returns primary key attribute hash. If using a composite primary key
|
|
573
514
|
# value such be an array with values for each primary key in the correct
|
|
@@ -595,7 +536,7 @@ module Sequel
|
|
|
595
536
|
# plan to join other tables to this table and you want the column references
|
|
596
537
|
# to be qualified.
|
|
597
538
|
#
|
|
598
|
-
# Artist.
|
|
539
|
+
# Artist.where(Artist.qualified_primary_key_hash(1))
|
|
599
540
|
# # SELECT * FROM artists WHERE (artists.id = 1)
|
|
600
541
|
def qualified_primary_key_hash(value, qualifier=table_name)
|
|
601
542
|
case key = @primary_key
|
|
@@ -610,27 +551,6 @@ module Sequel
|
|
|
610
551
|
end
|
|
611
552
|
end
|
|
612
553
|
|
|
613
|
-
# Similar to finder, but uses a prepared statement instead of a placeholder
|
|
614
|
-
# literalizer. This makes the SQL used static (cannot vary per call), but
|
|
615
|
-
# allows binding argument values instead of literalizing them into the SQL
|
|
616
|
-
# query string.
|
|
617
|
-
#
|
|
618
|
-
# If a block is used with this method, it is instance_execed by the model,
|
|
619
|
-
# and should accept the desired number of placeholder arguments.
|
|
620
|
-
#
|
|
621
|
-
# The options are the same as the options for finder, with the following
|
|
622
|
-
# exception:
|
|
623
|
-
# :type :: Specifies the type of prepared statement to create
|
|
624
|
-
def prepared_finder(meth=OPTS, opts=OPTS, &block)
|
|
625
|
-
if block
|
|
626
|
-
raise Error, "cannot pass both a method name argument and a block of Model.finder" unless meth.is_a?(Hash)
|
|
627
|
-
meth = meth.merge(:prepare=>true)
|
|
628
|
-
else
|
|
629
|
-
opts = opts.merge(:prepare=>true)
|
|
630
|
-
end
|
|
631
|
-
finder(meth, opts, &block)
|
|
632
|
-
end
|
|
633
|
-
|
|
634
554
|
# Restrict the setting of the primary key(s) when using mass assignment (e.g. +set+). Because
|
|
635
555
|
# this is the default, this only make sense to use in a subclass where the
|
|
636
556
|
# parent class has used +unrestrict_primary_key+.
|
|
@@ -645,22 +565,6 @@ module Sequel
|
|
|
645
565
|
@restrict_primary_key
|
|
646
566
|
end
|
|
647
567
|
|
|
648
|
-
# Set the columns to allow when using mass assignment (e.g. +set+). Using this means that
|
|
649
|
-
# any columns not listed here will not be modified. If you have any virtual
|
|
650
|
-
# setter methods (methods that end in =) that you want to be used during
|
|
651
|
-
# mass assignment, they need to be listed here as well (without the =).
|
|
652
|
-
#
|
|
653
|
-
# It may be better to use a method such as +set_only+ or +set_fields+ that lets you specify
|
|
654
|
-
# the allowed fields per call.
|
|
655
|
-
#
|
|
656
|
-
# Artist.set_allowed_columns(:name, :hometown)
|
|
657
|
-
# Artist.set(:name=>'Bob', :hometown=>'Sactown') # No Error
|
|
658
|
-
# Artist.set(:name=>'Bob', :records_sold=>30000) # Error
|
|
659
|
-
def set_allowed_columns(*cols)
|
|
660
|
-
clear_setter_methods_cache
|
|
661
|
-
@allowed_columns = cols
|
|
662
|
-
end
|
|
663
|
-
|
|
664
568
|
# Sets the dataset associated with the Model class. +ds+ can be a +Symbol+,
|
|
665
569
|
# +LiteralString+, <tt>SQL::Identifier</tt>, <tt>SQL::QualifiedIdentifier</tt>,
|
|
666
570
|
# <tt>SQL::AliasedExpression</tt>
|
|
@@ -670,36 +574,43 @@ module Sequel
|
|
|
670
574
|
# database with the table name given. Other arguments raise an +Error+.
|
|
671
575
|
# Returns self.
|
|
672
576
|
#
|
|
673
|
-
# This changes the row_proc of the dataset to return
|
|
674
|
-
# model objects and extends the dataset with the dataset_method_modules.
|
|
675
577
|
# It also attempts to determine the database schema for the model,
|
|
676
578
|
# based on the given dataset.
|
|
677
579
|
#
|
|
678
|
-
# Artist.set_dataset(:tbl_artists)
|
|
679
|
-
# Artist.set_dataset(DB[:artists])
|
|
680
|
-
#
|
|
681
580
|
# Note that you should not use this to change the model's dataset
|
|
682
581
|
# at runtime. If you have that need, you should look into Sequel's
|
|
683
|
-
# sharding support
|
|
582
|
+
# sharding support, or creating a separate Model class per dataset
|
|
583
|
+
#
|
|
584
|
+
# You should avoid calling this method directly if possible. Instead you should
|
|
585
|
+
# set the table name or dataset when creating the model class:
|
|
586
|
+
#
|
|
587
|
+
# # table name
|
|
588
|
+
# class Artist < Sequel::Model(:tbl_artists)
|
|
589
|
+
# end
|
|
590
|
+
#
|
|
591
|
+
# # dataset
|
|
592
|
+
# class Artist < Sequel::Model(DB[:tbl_artists])
|
|
593
|
+
# end
|
|
684
594
|
def set_dataset(ds, opts=OPTS)
|
|
685
595
|
inherited = opts[:inherited]
|
|
686
596
|
@dataset = convert_input_dataset(ds)
|
|
687
|
-
@require_modification =
|
|
597
|
+
@require_modification = @dataset.provides_accurate_rows_matched? if require_modification.nil?
|
|
688
598
|
if inherited
|
|
689
599
|
self.simple_table = superclass.simple_table
|
|
690
|
-
@columns =
|
|
600
|
+
@columns = superclass.instance_variable_get(:@columns)
|
|
601
|
+
@db_schema = superclass.instance_variable_get(:@db_schema)
|
|
691
602
|
else
|
|
692
|
-
@
|
|
603
|
+
@dataset = @dataset.with_extend(*@dataset_method_modules.reverse)
|
|
604
|
+
@db_schema = get_db_schema
|
|
693
605
|
end
|
|
694
|
-
|
|
695
|
-
check_non_connection_error{@db_schema = (inherited ? superclass.db_schema : get_db_schema)}
|
|
606
|
+
|
|
696
607
|
reset_instance_dataset
|
|
697
608
|
self
|
|
698
609
|
end
|
|
699
610
|
|
|
700
611
|
# Sets the primary key for this model. You can use either a regular
|
|
701
612
|
# or a composite primary key. To not use a primary key, set to nil
|
|
702
|
-
# or use +no_primary_key+.
|
|
613
|
+
# or use +no_primary_key+. On most adapters, Sequel can automatically
|
|
703
614
|
# determine the primary key to use, so this method is not needed often.
|
|
704
615
|
#
|
|
705
616
|
# class Person < Sequel::Model
|
|
@@ -721,48 +632,22 @@ module Sequel
|
|
|
721
632
|
end
|
|
722
633
|
end
|
|
723
634
|
self.simple_pk = if key && !key.is_a?(Array)
|
|
724
|
-
(@dataset || db).literal(key)
|
|
635
|
+
(@dataset || db).literal(key).freeze
|
|
725
636
|
end
|
|
726
637
|
@primary_key = key
|
|
727
638
|
end
|
|
728
639
|
|
|
729
|
-
# Cache of setter methods to allow by default, in order to speed up
|
|
640
|
+
# Cache of setter methods to allow by default, in order to speed up mass assignment.
|
|
730
641
|
def setter_methods
|
|
731
|
-
@setter_methods
|
|
642
|
+
@setter_methods || (@setter_methods = get_setter_methods)
|
|
732
643
|
end
|
|
733
644
|
|
|
734
|
-
# Sets up a dataset method that returns a filtered dataset.
|
|
735
|
-
# Sometimes thought of as a scope, and like most dataset methods,
|
|
736
|
-
# they can be chained.
|
|
737
|
-
# For example:
|
|
738
|
-
#
|
|
739
|
-
# Topic.subset(:joes, :username.like('%joe%'))
|
|
740
|
-
# Topic.subset(:popular){num_posts > 100}
|
|
741
|
-
# Topic.subset(:recent){created_on > Date.today - 7}
|
|
742
|
-
#
|
|
743
|
-
# Allows you to do:
|
|
744
|
-
#
|
|
745
|
-
# Topic.joes.recent.popular
|
|
746
|
-
#
|
|
747
|
-
# to get topics with a username that includes joe that
|
|
748
|
-
# have more than 100 posts and were created less than
|
|
749
|
-
# 7 days ago.
|
|
750
|
-
#
|
|
751
|
-
# Both the args given and the block are passed to <tt>Dataset#filter</tt>.
|
|
752
|
-
#
|
|
753
|
-
# This method creates dataset methods that do not accept arguments. To create
|
|
754
|
-
# dataset methods that accept arguments, you should use define a
|
|
755
|
-
# method directly inside a #dataset_module block.
|
|
756
|
-
def subset(name, *args, &block)
|
|
757
|
-
def_dataset_method(name){filter(*args, &block)}
|
|
758
|
-
end
|
|
759
|
-
|
|
760
645
|
# Returns name of primary table for the dataset. If the table for the dataset
|
|
761
646
|
# is aliased, returns the aliased name.
|
|
762
647
|
#
|
|
763
648
|
# Artist.table_name # => :artists
|
|
764
649
|
# Sequel::Model(:foo).table_name # => :foo
|
|
765
|
-
# Sequel::Model(:
|
|
650
|
+
# Sequel::Model(Sequel[:foo].as(:bar)).table_name # => :bar
|
|
766
651
|
def table_name
|
|
767
652
|
dataset.first_source_alias
|
|
768
653
|
end
|
|
@@ -770,9 +655,9 @@ module Sequel
|
|
|
770
655
|
# Allow the setting of the primary key(s) when using the mass assignment methods.
|
|
771
656
|
# Using this method can open up security issues, be very careful before using it.
|
|
772
657
|
#
|
|
773
|
-
# Artist.set(:
|
|
658
|
+
# Artist.set(id: 1) # Error
|
|
774
659
|
# Artist.unrestrict_primary_key
|
|
775
|
-
# Artist.set(:
|
|
660
|
+
# Artist.set(id: 1) # No Error
|
|
776
661
|
def unrestrict_primary_key
|
|
777
662
|
clear_setter_methods_cache
|
|
778
663
|
@restrict_primary_key = false
|
|
@@ -789,18 +674,18 @@ module Sequel
|
|
|
789
674
|
end
|
|
790
675
|
|
|
791
676
|
# Add model methods that call dataset methods
|
|
792
|
-
Plugins.def_dataset_methods(self,
|
|
677
|
+
Plugins.def_dataset_methods(self, (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS + [:each_server]) - [:<<, :or, :[], :columns, :columns!, :delete, :update, :set_graph_aliases, :add_graph_aliases])
|
|
793
678
|
|
|
794
679
|
private
|
|
795
680
|
|
|
796
|
-
# Yield to the passed block and swallow all errors other than DatabaseConnectionErrors.
|
|
797
|
-
def check_non_connection_error
|
|
681
|
+
# Yield to the passed block and if do_raise is false, swallow all errors other than DatabaseConnectionErrors.
|
|
682
|
+
def check_non_connection_error(do_raise=require_valid_table)
|
|
798
683
|
begin
|
|
799
|
-
yield
|
|
684
|
+
db.transaction(:savepoint=>:only){yield}
|
|
800
685
|
rescue Sequel::DatabaseConnectionError
|
|
801
686
|
raise
|
|
802
|
-
rescue
|
|
803
|
-
|
|
687
|
+
rescue Sequel::Error
|
|
688
|
+
raise if do_raise
|
|
804
689
|
end
|
|
805
690
|
end
|
|
806
691
|
|
|
@@ -809,25 +694,27 @@ module Sequel
|
|
|
809
694
|
def convert_input_dataset(ds)
|
|
810
695
|
case ds
|
|
811
696
|
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
|
|
812
|
-
self.simple_table = db.literal(ds)
|
|
697
|
+
self.simple_table = db.literal(ds).freeze
|
|
813
698
|
ds = db.from(ds)
|
|
814
699
|
when Dataset
|
|
700
|
+
ds = ds.from_self(:alias=>ds.first_source) if ds.joined_dataset?
|
|
701
|
+
|
|
815
702
|
self.simple_table = if ds.send(:simple_select_all?)
|
|
816
|
-
ds.literal(ds.first_source_table)
|
|
703
|
+
ds.literal(ds.first_source_table).freeze
|
|
817
704
|
end
|
|
818
705
|
@db = ds.db
|
|
819
706
|
else
|
|
820
707
|
raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
|
|
821
708
|
end
|
|
822
|
-
|
|
823
|
-
ds
|
|
709
|
+
|
|
710
|
+
set_dataset_row_proc(ds.clone(:model=>self))
|
|
824
711
|
end
|
|
825
712
|
|
|
826
713
|
# Add the module to the class's dataset_method_modules. Extend the dataset with the
|
|
827
714
|
# module if the model has a dataset. Add dataset methods to the class for all
|
|
828
715
|
# public dataset methods.
|
|
829
716
|
def dataset_extend(mod, opts=OPTS)
|
|
830
|
-
@dataset.
|
|
717
|
+
@dataset = @dataset.with_extend(mod) if @dataset
|
|
831
718
|
reset_instance_dataset
|
|
832
719
|
dataset_method_modules << mod
|
|
833
720
|
unless opts[:create_class_methods] == false
|
|
@@ -837,9 +724,11 @@ module Sequel
|
|
|
837
724
|
|
|
838
725
|
# Create a column accessor for a column with a method name that is hard to use in ruby code.
|
|
839
726
|
def def_bad_column_accessor(column)
|
|
727
|
+
im = instance_methods
|
|
840
728
|
overridable_methods_module.module_eval do
|
|
841
|
-
|
|
842
|
-
define_method(
|
|
729
|
+
meth = :"#{column}="
|
|
730
|
+
define_method(column){self[column]} unless im.include?(column)
|
|
731
|
+
define_method(meth){|v| self[column] = v} unless im.include?(meth)
|
|
843
732
|
end
|
|
844
733
|
end
|
|
845
734
|
|
|
@@ -847,51 +736,28 @@ module Sequel
|
|
|
847
736
|
# use a string to define the method for speed. For other columns names, use a block.
|
|
848
737
|
def def_column_accessor(*columns)
|
|
849
738
|
clear_setter_methods_cache
|
|
850
|
-
columns, bad_columns = columns.partition{|x|
|
|
739
|
+
columns, bad_columns = columns.partition{|x| /\A[A-Za-z_][A-Za-z0-9_]*\z/.match(x.to_s)}
|
|
851
740
|
bad_columns.each{|x| def_bad_column_accessor(x)}
|
|
852
|
-
im = instance_methods
|
|
741
|
+
im = instance_methods
|
|
853
742
|
columns.each do |column|
|
|
854
|
-
meth = "#{column}="
|
|
855
|
-
overridable_methods_module.module_eval("def #{column}; self[:#{column}] end", __FILE__, __LINE__) unless im.include?(column
|
|
743
|
+
meth = :"#{column}="
|
|
744
|
+
overridable_methods_module.module_eval("def #{column}; self[:#{column}] end", __FILE__, __LINE__) unless im.include?(column)
|
|
856
745
|
overridable_methods_module.module_eval("def #{meth}(v); self[:#{column}] = v end", __FILE__, __LINE__) unless im.include?(meth)
|
|
857
746
|
end
|
|
858
747
|
end
|
|
859
748
|
|
|
860
749
|
# Define a model method that calls the dataset method with the same name,
|
|
861
|
-
# only used for methods with names that can't be
|
|
750
|
+
# only used for methods with names that can't be represented directly in
|
|
862
751
|
# ruby code.
|
|
863
752
|
def def_model_dataset_method(meth)
|
|
864
753
|
return if respond_to?(meth, true)
|
|
865
754
|
|
|
866
|
-
if meth.to_s =~
|
|
755
|
+
if meth.to_s =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
|
867
756
|
instance_eval("def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end", __FILE__, __LINE__)
|
|
868
757
|
else
|
|
869
|
-
(
|
|
758
|
+
define_singleton_method(meth){|*args, &block| dataset.public_send(meth, *args, &block)}
|
|
870
759
|
end
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
# Define a finder method in the given module with the given method name that
|
|
874
|
-
# load rows using the finder with the given name.
|
|
875
|
-
def def_finder_method(mod, meth, type)
|
|
876
|
-
mod.send(:define_method, meth){|*args, &block| finder_for(meth).send(type, *args, &block)}
|
|
877
|
-
end
|
|
878
|
-
|
|
879
|
-
# Define a prepared_finder method in the given module that will call the associated prepared
|
|
880
|
-
# statement.
|
|
881
|
-
def def_prepare_method(mod, meth)
|
|
882
|
-
mod.send(:define_method, meth){|*args, &block| finder_for(meth).call(prepare_method_arg_hash(args), &block)}
|
|
883
|
-
end
|
|
884
|
-
|
|
885
|
-
# Find the finder to use for the give method. If a finder has not been loaded
|
|
886
|
-
# for the method, load the finder and set correctly in the finders hash, then
|
|
887
|
-
# return the finder.
|
|
888
|
-
def finder_for(meth)
|
|
889
|
-
unless finder = Sequel.synchronize{@finders[meth]}
|
|
890
|
-
finder_loader = @finder_loaders.fetch(meth)
|
|
891
|
-
finder = finder_loader.call(self)
|
|
892
|
-
Sequel.synchronize{@finders[meth] = finder}
|
|
893
|
-
end
|
|
894
|
-
finder
|
|
760
|
+
singleton_class.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
|
895
761
|
end
|
|
896
762
|
|
|
897
763
|
# Get the schema from the database, fall back on checking the columns
|
|
@@ -903,14 +769,14 @@ module Sequel
|
|
|
903
769
|
schema_hash = {}
|
|
904
770
|
ds_opts = dataset.opts
|
|
905
771
|
get_columns = proc{check_non_connection_error{columns} || []}
|
|
906
|
-
schema_array = check_non_connection_error{db.schema(dataset, :reload=>reload)} if db.supports_schema_parsing?
|
|
772
|
+
schema_array = check_non_connection_error(false){db.schema(dataset, :reload=>reload)} if db.supports_schema_parsing?
|
|
907
773
|
if schema_array
|
|
908
774
|
schema_array.each{|k,v| schema_hash[k] = v}
|
|
909
775
|
|
|
910
776
|
# Set the primary key(s) based on the schema information,
|
|
911
777
|
# if the schema information includes primary key information
|
|
912
778
|
if schema_array.all?{|k,v| v.has_key?(:primary_key)}
|
|
913
|
-
pks = schema_array.
|
|
779
|
+
pks = schema_array.map{|k,v| k if v[:primary_key]}.compact
|
|
914
780
|
pks.length > 0 ? set_primary_key(pks) : no_primary_key
|
|
915
781
|
end
|
|
916
782
|
|
|
@@ -925,11 +791,11 @@ module Sequel
|
|
|
925
791
|
# Dataset is for a single table with all columns,
|
|
926
792
|
# so set the columns based on the order they were
|
|
927
793
|
# returned by the schema.
|
|
928
|
-
cols = schema_array.
|
|
794
|
+
cols = schema_array.map{|k,v| k}
|
|
929
795
|
set_columns(cols)
|
|
930
796
|
# Also set the columns for the dataset, so the dataset
|
|
931
797
|
# doesn't have to do a query to get them.
|
|
932
|
-
dataset.
|
|
798
|
+
dataset.send(:columns=, cols)
|
|
933
799
|
end
|
|
934
800
|
else
|
|
935
801
|
# If the dataset uses multiple tables or custom sql or getting
|
|
@@ -943,21 +809,81 @@ module Sequel
|
|
|
943
809
|
# Uncached version of setter_methods, to be overridden by plugins
|
|
944
810
|
# that want to modify the methods used.
|
|
945
811
|
def get_setter_methods
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
meths = instance_methods.collect(&:to_s).grep(SETTER_METHOD_REGEXP) - RESTRICTED_SETTER_METHODS
|
|
950
|
-
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && restrict_primary_key?
|
|
951
|
-
meths
|
|
952
|
-
end
|
|
812
|
+
meths = instance_methods.map(&:to_s).select{|l| l.end_with?('=')} - RESTRICTED_SETTER_METHODS
|
|
813
|
+
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && restrict_primary_key?
|
|
814
|
+
meths
|
|
953
815
|
end
|
|
954
816
|
|
|
817
|
+
# If possible, set the dataset for the model subclass as soon as it
|
|
818
|
+
# is created. Also, make sure the inherited class instance variables
|
|
819
|
+
# are copied into the subclass.
|
|
820
|
+
#
|
|
821
|
+
# Sequel queries the database to get schema information as soon as
|
|
822
|
+
# a model class is created:
|
|
823
|
+
#
|
|
824
|
+
# class Artist < Sequel::Model # Causes schema query
|
|
825
|
+
# end
|
|
826
|
+
def inherited(subclass)
|
|
827
|
+
super
|
|
828
|
+
ivs = subclass.instance_variables
|
|
829
|
+
inherited_instance_variables.each do |iv, dup|
|
|
830
|
+
if (sup_class_value = instance_variable_get(iv)) && dup
|
|
831
|
+
sup_class_value = case dup
|
|
832
|
+
when :dup
|
|
833
|
+
sup_class_value.dup
|
|
834
|
+
when :hash_dup
|
|
835
|
+
h = {}
|
|
836
|
+
sup_class_value.each{|k,v| h[k] = v.dup}
|
|
837
|
+
h
|
|
838
|
+
when Proc
|
|
839
|
+
dup.call(sup_class_value)
|
|
840
|
+
else
|
|
841
|
+
raise Error, "bad inherited instance variable type: #{dup.inspect}"
|
|
842
|
+
end
|
|
843
|
+
end
|
|
844
|
+
subclass.instance_variable_set(iv, sup_class_value)
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
unless ivs.include?(:@dataset)
|
|
848
|
+
if @dataset && self != Model
|
|
849
|
+
subclass.set_dataset(@dataset.clone, :inherited=>true)
|
|
850
|
+
elsif (n = subclass.name) && !n.to_s.empty?
|
|
851
|
+
db
|
|
852
|
+
subclass.set_dataset(subclass.implicit_table_name)
|
|
853
|
+
end
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
|
|
955
857
|
# A hash of instance variables to automatically set up in subclasses.
|
|
956
|
-
#
|
|
957
|
-
#
|
|
958
|
-
#
|
|
858
|
+
# Keys are instance variable symbols, values should be:
|
|
859
|
+
# nil :: Assign directly from superclass to subclass (frozen objects)
|
|
860
|
+
# :dup :: Dup object when assigning from superclass to subclass (mutable objects)
|
|
861
|
+
# :hash_dup :: Assign hash with same keys, but dup all the values
|
|
862
|
+
# Proc :: Call with subclass to do the assignment
|
|
959
863
|
def inherited_instance_variables
|
|
960
|
-
|
|
864
|
+
{
|
|
865
|
+
:@cache_anonymous_models=>nil,
|
|
866
|
+
:@dataset_method_modules=>:dup,
|
|
867
|
+
:@dataset_module_class=>nil,
|
|
868
|
+
:@db=>nil,
|
|
869
|
+
:@default_set_fields_options=>:dup,
|
|
870
|
+
:@fast_instance_delete_sql=>nil,
|
|
871
|
+
:@fast_pk_lookup_sql=>nil,
|
|
872
|
+
:@plugins=>:dup,
|
|
873
|
+
:@primary_key=>nil,
|
|
874
|
+
:@raise_on_save_failure=>nil,
|
|
875
|
+
:@raise_on_typecast_failure=>nil,
|
|
876
|
+
:@require_modification=>nil,
|
|
877
|
+
:@require_valid_table=>nil,
|
|
878
|
+
:@restrict_primary_key=>nil,
|
|
879
|
+
:@setter_methods=>nil,
|
|
880
|
+
:@simple_pk=>nil,
|
|
881
|
+
:@simple_table=>nil,
|
|
882
|
+
:@strict_param_setting=>nil,
|
|
883
|
+
:@typecast_empty_string_to_nil=>nil,
|
|
884
|
+
:@typecast_on_assignment=>nil,
|
|
885
|
+
:@use_transactions=>nil
|
|
886
|
+
}
|
|
961
887
|
end
|
|
962
888
|
|
|
963
889
|
# For the given opts hash and default name or :class option, add a
|
|
@@ -968,11 +894,24 @@ module Sequel
|
|
|
968
894
|
case opts[:class]
|
|
969
895
|
when String, Symbol
|
|
970
896
|
# Delete :class to allow late binding
|
|
971
|
-
|
|
897
|
+
class_name = opts.delete(:class).to_s
|
|
898
|
+
|
|
899
|
+
if (namespace = opts[:class_namespace]) && !class_name.start_with?('::')
|
|
900
|
+
class_name = "::#{namespace}::#{class_name}"
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
opts[:class_name] ||= class_name
|
|
972
904
|
when Class
|
|
973
905
|
opts[:class_name] ||= opts[:class].name
|
|
974
906
|
end
|
|
975
|
-
|
|
907
|
+
|
|
908
|
+
opts[:class_name] ||= '::' + ((name || '').split("::")[0..-2] + [camelize(default)]).join('::')
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
# Clear the setter_methods cache when a setter method is added.
|
|
912
|
+
def method_added(meth)
|
|
913
|
+
clear_setter_methods_cache if meth.to_s.end_with?('=')
|
|
914
|
+
super
|
|
976
915
|
end
|
|
977
916
|
|
|
978
917
|
# Module that the class includes that holds methods the class adds for column accessors and
|
|
@@ -986,51 +925,12 @@ module Sequel
|
|
|
986
925
|
# defined, the corresponding plugin required.
|
|
987
926
|
def plugin_module(plugin)
|
|
988
927
|
module_name = plugin.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
Sequel::Plugins.const_get(module_name) == Sequel.const_get(module_name))
|
|
992
|
-
begin
|
|
993
|
-
require "sequel/plugins/#{plugin}"
|
|
994
|
-
rescue LoadError => e
|
|
995
|
-
begin
|
|
996
|
-
require "sequel_#{plugin}"
|
|
997
|
-
rescue LoadError => e2
|
|
998
|
-
e.message << "; #{e2.message}"
|
|
999
|
-
raise e
|
|
1000
|
-
end
|
|
1001
|
-
end
|
|
928
|
+
unless Sequel::Plugins.const_defined?(module_name, false)
|
|
929
|
+
require "sequel/plugins/#{plugin}"
|
|
1002
930
|
end
|
|
1003
931
|
Sequel::Plugins.const_get(module_name)
|
|
1004
932
|
end
|
|
1005
933
|
|
|
1006
|
-
# Check if the plugin module +plugin+ defines the constant named by +submod+.
|
|
1007
|
-
def plugin_module_defined?(plugin, submod)
|
|
1008
|
-
if RUBY_VERSION >= '1.9'
|
|
1009
|
-
plugin.const_defined?(submod, false)
|
|
1010
|
-
else
|
|
1011
|
-
# :nocov:
|
|
1012
|
-
plugin.const_defined?(submod)
|
|
1013
|
-
# :nocov:
|
|
1014
|
-
end
|
|
1015
|
-
end
|
|
1016
|
-
|
|
1017
|
-
# An hash of prepared argument values for the given arguments, with keys
|
|
1018
|
-
# starting at a. Used by the methods created by prepared_finder.
|
|
1019
|
-
def prepare_method_arg_hash(args)
|
|
1020
|
-
h = {}
|
|
1021
|
-
prepare_method_args('a', args.length).zip(args).each{|k, v| h[k] = v}
|
|
1022
|
-
h
|
|
1023
|
-
end
|
|
1024
|
-
|
|
1025
|
-
# An array of prepared statement argument names, of length n and starting with base.
|
|
1026
|
-
def prepare_method_args(base, n)
|
|
1027
|
-
(0...n).map do
|
|
1028
|
-
s = base.to_sym
|
|
1029
|
-
base = base.next
|
|
1030
|
-
s
|
|
1031
|
-
end
|
|
1032
|
-
end
|
|
1033
|
-
|
|
1034
934
|
# Find the row in the dataset that matches the primary key. Uses
|
|
1035
935
|
# a static SQL optimization if the table and primary key are simple.
|
|
1036
936
|
#
|
|
@@ -1044,10 +944,8 @@ module Sequel
|
|
|
1044
944
|
ds.literal_append(sql, pk)
|
|
1045
945
|
ds.fetch_rows(sql){|r| return ds.row_proc.call(r)}
|
|
1046
946
|
nil
|
|
1047
|
-
elsif dataset.joined_dataset?
|
|
1048
|
-
first_where(qualified_primary_key_hash(pk))
|
|
1049
947
|
else
|
|
1050
|
-
|
|
948
|
+
dataset.first(primary_key_hash(pk))
|
|
1051
949
|
end
|
|
1052
950
|
end
|
|
1053
951
|
|
|
@@ -1060,18 +958,17 @@ module Sequel
|
|
|
1060
958
|
# are used, or set it to nil if not used.
|
|
1061
959
|
def reset_fast_pk_lookup_sql
|
|
1062
960
|
@fast_pk_lookup_sql = if @simple_table && @simple_pk
|
|
1063
|
-
"SELECT * FROM
|
|
961
|
+
"SELECT * FROM #{@simple_table} WHERE #{@simple_pk} = ".freeze
|
|
1064
962
|
end
|
|
1065
963
|
@fast_instance_delete_sql = if @simple_table && @simple_pk
|
|
1066
|
-
"DELETE FROM
|
|
964
|
+
"DELETE FROM #{@simple_table} WHERE #{@simple_pk} = ".freeze
|
|
1067
965
|
end
|
|
1068
966
|
end
|
|
1069
967
|
|
|
1070
968
|
# Reset the instance dataset to a modified copy of the current dataset,
|
|
1071
969
|
# should be used whenever the model's dataset is modified.
|
|
1072
970
|
def reset_instance_dataset
|
|
1073
|
-
@
|
|
1074
|
-
@instance_dataset = @dataset.limit(1).naked if @dataset
|
|
971
|
+
@instance_dataset = @dataset.limit(1).naked.skip_limit_check if @dataset
|
|
1075
972
|
end
|
|
1076
973
|
|
|
1077
974
|
# Set the columns for this model and create accessor methods for each column.
|
|
@@ -1083,7 +980,7 @@ module Sequel
|
|
|
1083
980
|
|
|
1084
981
|
# Set the dataset's row_proc to the current model.
|
|
1085
982
|
def set_dataset_row_proc(ds)
|
|
1086
|
-
ds.
|
|
983
|
+
ds.with_row_proc(self)
|
|
1087
984
|
end
|
|
1088
985
|
|
|
1089
986
|
# Reset the fast primary key lookup SQL when the simple_pk value changes.
|
|
@@ -1107,36 +1004,43 @@ module Sequel
|
|
|
1107
1004
|
|
|
1108
1005
|
# Sequel::Model instance methods that implement basic model functionality.
|
|
1109
1006
|
#
|
|
1110
|
-
# * All of the
|
|
1007
|
+
# * All of the model before/after/around hooks are implemented as instance methods that are called
|
|
1111
1008
|
# by Sequel when the appropriate action occurs. For example, when destroying
|
|
1112
1009
|
# a model object, Sequel will call +around_destroy+, which will call +before_destroy+, do
|
|
1113
1010
|
# the destroy, and then call +after_destroy+.
|
|
1114
1011
|
# * The following instance_methods all call the class method of the same
|
|
1115
1012
|
# name: columns, db, primary_key, db_schema.
|
|
1116
|
-
# *
|
|
1117
|
-
#
|
|
1118
|
-
#
|
|
1119
|
-
#
|
|
1013
|
+
# * The following accessor methods are defined via metaprogramming:
|
|
1014
|
+
# raise_on_save_failure, raise_on_typecast_failure, require_modification,
|
|
1015
|
+
# strict_param_setting, typecast_empty_string_to_nil, typecast_on_assignment,
|
|
1016
|
+
# and use_transactions. The setter methods will change the setting for the
|
|
1017
|
+
# instance, and the getter methods will check for an instance setting, then
|
|
1018
|
+
# try the class setting if no instance setting has been set.
|
|
1120
1019
|
module InstanceMethods
|
|
1121
1020
|
HOOKS.each{|h| class_eval("def #{h}; end", __FILE__, __LINE__)}
|
|
1122
|
-
|
|
1021
|
+
[:around_create, :around_update, :around_save, :around_destroy, :around_validation].each{|h| class_eval("def #{h}; yield end", __FILE__, __LINE__)}
|
|
1123
1022
|
|
|
1124
1023
|
# Define instance method(s) that calls class method(s) of the
|
|
1125
1024
|
# same name. Replaces the construct:
|
|
1126
1025
|
#
|
|
1127
|
-
# define_method(meth){self.class.
|
|
1026
|
+
# define_method(meth){self.class.public_send(meth)}
|
|
1128
1027
|
[:columns, :db, :primary_key, :db_schema].each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
|
|
1129
1028
|
|
|
1130
1029
|
# Define instance method(s) that calls class method(s) of the
|
|
1131
1030
|
# same name, caching the result in an instance variable. Define
|
|
1132
1031
|
# standard attr_writer method for modifying that instance variable.
|
|
1133
|
-
|
|
1134
|
-
|
|
1032
|
+
[:typecast_empty_string_to_nil, :typecast_on_assignment, :strict_param_setting,
|
|
1033
|
+
:raise_on_save_failure, :raise_on_typecast_failure, :require_modification, :use_transactions].each do |meth|
|
|
1034
|
+
class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)
|
|
1035
|
+
attr_writer(meth)
|
|
1036
|
+
end
|
|
1135
1037
|
|
|
1136
1038
|
# The hash of attribute values. Keys are symbols with the names of the
|
|
1137
|
-
# underlying database columns.
|
|
1039
|
+
# underlying database columns. The returned hash is a reference to the
|
|
1040
|
+
# receiver's values hash, and modifying it will also modify the receiver's
|
|
1041
|
+
# values.
|
|
1138
1042
|
#
|
|
1139
|
-
# Artist.new(:
|
|
1043
|
+
# Artist.new(name: 'Bob').values # => {:name=>'Bob'}
|
|
1140
1044
|
# Artist[1].values # => {:id=>1, :name=>'Jim', ...}
|
|
1141
1045
|
attr_reader :values
|
|
1142
1046
|
alias to_hash values
|
|
@@ -1147,7 +1051,7 @@ module Sequel
|
|
|
1147
1051
|
# method names.
|
|
1148
1052
|
alias get_column_value send
|
|
1149
1053
|
|
|
1150
|
-
# Set the value of the column. Takes two
|
|
1054
|
+
# Set the value of the column. Takes two arguments. The first is a
|
|
1151
1055
|
# symbol or string argument for the column name, suffixed with =. The
|
|
1152
1056
|
# second is the value to set for the column. By default it calls send
|
|
1153
1057
|
# with the argument to set the value. This can be overridden if you have
|
|
@@ -1161,17 +1065,17 @@ module Sequel
|
|
|
1161
1065
|
# Arguments:
|
|
1162
1066
|
# values :: should be a hash to pass to set.
|
|
1163
1067
|
#
|
|
1164
|
-
# Artist.new(:
|
|
1068
|
+
# Artist.new(name: 'Bob')
|
|
1165
1069
|
#
|
|
1166
1070
|
# Artist.new do |a|
|
|
1167
1071
|
# a.name = 'Bob'
|
|
1168
1072
|
# end
|
|
1169
|
-
def initialize(values =
|
|
1073
|
+
def initialize(values = OPTS)
|
|
1170
1074
|
@values = {}
|
|
1171
1075
|
@new = true
|
|
1172
1076
|
@modified = true
|
|
1173
1077
|
initialize_set(values)
|
|
1174
|
-
|
|
1078
|
+
_clear_changed_columns(:initialize)
|
|
1175
1079
|
yield self if block_given?
|
|
1176
1080
|
end
|
|
1177
1081
|
|
|
@@ -1207,16 +1111,33 @@ module Sequel
|
|
|
1207
1111
|
eql?(obj)
|
|
1208
1112
|
end
|
|
1209
1113
|
|
|
1210
|
-
#
|
|
1211
|
-
#
|
|
1114
|
+
# Case equality. By default, checks equality of the primary key value, see
|
|
1115
|
+
# pk_equal?.
|
|
1212
1116
|
#
|
|
1213
|
-
# Artist[1] === Artist[1] # true
|
|
1214
|
-
# Artist.new === Artist.new # false
|
|
1215
|
-
# Artist[1].set(:name=>'Bob')
|
|
1117
|
+
# Artist[1] === Artist[1] # => true
|
|
1118
|
+
# Artist.new === Artist.new # => false
|
|
1119
|
+
# Artist[1].set(:name=>'Bob') === Artist[1] # => true
|
|
1216
1120
|
def ===(obj)
|
|
1217
|
-
|
|
1121
|
+
case pkv = pk
|
|
1122
|
+
when nil
|
|
1123
|
+
return false
|
|
1124
|
+
when Array
|
|
1125
|
+
return false if pkv.any?(&:nil?)
|
|
1126
|
+
end
|
|
1127
|
+
|
|
1128
|
+
(obj.class == model) && (obj.pk == pkv)
|
|
1218
1129
|
end
|
|
1219
|
-
|
|
1130
|
+
|
|
1131
|
+
# If the receiver has a primary key value, returns true if the objects have
|
|
1132
|
+
# the same class and primary key value.
|
|
1133
|
+
# If the receiver's primary key value is nil or is an array containing
|
|
1134
|
+
# nil, returns false.
|
|
1135
|
+
#
|
|
1136
|
+
# Artist[1].pk_equal?(Artist[1]) # => true
|
|
1137
|
+
# Artist.new.pk_equal?(Artist.new) # => false
|
|
1138
|
+
# Artist[1].set(:name=>'Bob').pk_equal?(Artist[1]) # => true
|
|
1139
|
+
alias pk_equal? ===
|
|
1140
|
+
|
|
1220
1141
|
# class is defined in Object, but it is also a keyword,
|
|
1221
1142
|
# and since a lot of instance methods call class methods,
|
|
1222
1143
|
# this alias makes it so you can use model instead of
|
|
@@ -1248,9 +1169,9 @@ module Sequel
|
|
|
1248
1169
|
# a.name = 'Bob'
|
|
1249
1170
|
# a.changed_columns # => [:name]
|
|
1250
1171
|
def changed_columns
|
|
1251
|
-
|
|
1172
|
+
_changed_columns
|
|
1252
1173
|
end
|
|
1253
|
-
|
|
1174
|
+
|
|
1254
1175
|
# Deletes and returns +self+. Does not run destroy hooks.
|
|
1255
1176
|
# Look into using +destroy+ instead.
|
|
1256
1177
|
#
|
|
@@ -1263,11 +1184,8 @@ module Sequel
|
|
|
1263
1184
|
end
|
|
1264
1185
|
|
|
1265
1186
|
# Like delete but runs hooks before and after delete.
|
|
1266
|
-
#
|
|
1267
|
-
#
|
|
1268
|
-
# the item from the database and returns self. Uses a transaction
|
|
1269
|
-
# if use_transactions is true or if the :transaction option is given and
|
|
1270
|
-
# true.
|
|
1187
|
+
# Uses a transaction if use_transactions is true or if the
|
|
1188
|
+
# :transaction option is given and true.
|
|
1271
1189
|
#
|
|
1272
1190
|
# Artist[1].destroy # BEGIN; DELETE FROM artists WHERE (id = 1); COMMIT;
|
|
1273
1191
|
# # => #<Artist {:id=>1, ...}>
|
|
@@ -1326,12 +1244,12 @@ module Sequel
|
|
|
1326
1244
|
# errors, or dataset.
|
|
1327
1245
|
def freeze
|
|
1328
1246
|
values.freeze
|
|
1329
|
-
|
|
1247
|
+
_changed_columns.freeze
|
|
1330
1248
|
unless errors.frozen?
|
|
1331
1249
|
validate
|
|
1332
1250
|
errors.freeze
|
|
1333
1251
|
end
|
|
1334
|
-
this
|
|
1252
|
+
this if !new? && model.primary_key
|
|
1335
1253
|
super
|
|
1336
1254
|
end
|
|
1337
1255
|
|
|
@@ -1339,9 +1257,9 @@ module Sequel
|
|
|
1339
1257
|
# the same class and values (if pk is nil).
|
|
1340
1258
|
#
|
|
1341
1259
|
# Artist[1].hash == Artist[1].hash # true
|
|
1342
|
-
# Artist[1].set(:
|
|
1260
|
+
# Artist[1].set(name: 'Bob').hash == Artist[1].hash # true
|
|
1343
1261
|
# Artist.new.hash == Artist.new.hash # true
|
|
1344
|
-
# Artist.new(:
|
|
1262
|
+
# Artist.new(name: 'Bob').hash == Artist.new.hash # false
|
|
1345
1263
|
def hash
|
|
1346
1264
|
case primary_key
|
|
1347
1265
|
when Array
|
|
@@ -1370,23 +1288,37 @@ module Sequel
|
|
|
1370
1288
|
# Returns the keys in +values+. May not include all column names.
|
|
1371
1289
|
#
|
|
1372
1290
|
# Artist.new.keys # => []
|
|
1373
|
-
# Artist.new(:
|
|
1291
|
+
# Artist.new(name: 'Bob').keys # => [:name]
|
|
1374
1292
|
# Artist[1].keys # => [:id, :name]
|
|
1375
1293
|
def keys
|
|
1376
1294
|
@values.keys
|
|
1377
1295
|
end
|
|
1378
1296
|
|
|
1379
|
-
# Refresh this record using +for_update+
|
|
1380
|
-
# This can be used to make sure no other
|
|
1381
|
-
# same time.
|
|
1297
|
+
# Refresh this record using +for_update+ (by default, or the specified style when given)
|
|
1298
|
+
# unless this is a new record. Returns self. This can be used to make sure no other
|
|
1299
|
+
# process is updating the record at the same time.
|
|
1300
|
+
#
|
|
1301
|
+
# If style is a string, it will be used directly. You should never pass a string
|
|
1302
|
+
# to this method that is derived from user input, as that can lead to
|
|
1303
|
+
# SQL injection.
|
|
1304
|
+
#
|
|
1305
|
+
# A symbol may be used for database independent locking behavior, but
|
|
1306
|
+
# all supported symbols have separate methods (e.g. for_update).
|
|
1307
|
+
#
|
|
1382
1308
|
#
|
|
1383
1309
|
# a = Artist[1]
|
|
1384
1310
|
# Artist.db.transaction do
|
|
1385
1311
|
# a.lock!
|
|
1386
1312
|
# a.update(:name=>'A')
|
|
1387
1313
|
# end
|
|
1388
|
-
|
|
1389
|
-
|
|
1314
|
+
#
|
|
1315
|
+
# a = Artist[2]
|
|
1316
|
+
# Artist.db.transaction do
|
|
1317
|
+
# a.lock!('FOR NO KEY UPDATE')
|
|
1318
|
+
# a.update(:name=>'B')
|
|
1319
|
+
# end
|
|
1320
|
+
def lock!(style=:update)
|
|
1321
|
+
_refresh(this.lock_style(style)) unless new?
|
|
1390
1322
|
self
|
|
1391
1323
|
end
|
|
1392
1324
|
|
|
@@ -1416,9 +1348,7 @@ module Sequel
|
|
|
1416
1348
|
# a.modified!(:name)
|
|
1417
1349
|
# a.name.gsub!(/[aeou]/, 'i')
|
|
1418
1350
|
def modified!(column=nil)
|
|
1419
|
-
|
|
1420
|
-
changed_columns << column
|
|
1421
|
-
end
|
|
1351
|
+
_add_changed_column(column) if column
|
|
1422
1352
|
@modified = true
|
|
1423
1353
|
end
|
|
1424
1354
|
|
|
@@ -1428,7 +1358,7 @@ module Sequel
|
|
|
1428
1358
|
#
|
|
1429
1359
|
# a = Artist[1]
|
|
1430
1360
|
# a.modified? # => false
|
|
1431
|
-
# a.set(:
|
|
1361
|
+
# a.set(name: 'Jim')
|
|
1432
1362
|
# a.modified? # => true
|
|
1433
1363
|
#
|
|
1434
1364
|
# If a column is given, specifically check if the given column has
|
|
@@ -1477,12 +1407,12 @@ module Sequel
|
|
|
1477
1407
|
model.primary_key_hash(pk)
|
|
1478
1408
|
end
|
|
1479
1409
|
|
|
1480
|
-
# Returns a hash mapping the receivers primary key column(s) to their values.
|
|
1410
|
+
# Returns a hash mapping the receivers qualified primary key column(s) to their values.
|
|
1481
1411
|
#
|
|
1482
1412
|
# Artist[1].qualified_pk_hash
|
|
1483
|
-
# # => {Sequel
|
|
1413
|
+
# # => {Sequel[:artists][:id]=>1}
|
|
1484
1414
|
# Artist[[1, 2]].qualified_pk_hash
|
|
1485
|
-
# # => {Sequel
|
|
1415
|
+
# # => {Sequel[:artists][:id1]=>1, Sequel[:artists][:id2]=>2}
|
|
1486
1416
|
def qualified_pk_hash(qualifier=model.table_name)
|
|
1487
1417
|
model.qualified_primary_key_hash(pk, qualifier)
|
|
1488
1418
|
end
|
|
@@ -1510,9 +1440,9 @@ module Sequel
|
|
|
1510
1440
|
# is valid and before hooks execute successfully. Fails if:
|
|
1511
1441
|
#
|
|
1512
1442
|
# * the record is not valid, or
|
|
1513
|
-
# * before_save
|
|
1514
|
-
# * the record is new and before_create
|
|
1515
|
-
# * the record is not new and before_update
|
|
1443
|
+
# * before_save calls cancel_action, or
|
|
1444
|
+
# * the record is new and before_create calls cancel_action, or
|
|
1445
|
+
# * the record is not new and before_update calls cancel_action.
|
|
1516
1446
|
#
|
|
1517
1447
|
# If +save+ fails and either raise_on_save_failure or the
|
|
1518
1448
|
# :raise_on_failure option is true, it raises ValidationFailed
|
|
@@ -1520,9 +1450,6 @@ module Sequel
|
|
|
1520
1450
|
#
|
|
1521
1451
|
# If it succeeds, it returns self.
|
|
1522
1452
|
#
|
|
1523
|
-
# You can provide an optional list of columns to update, in which
|
|
1524
|
-
# case it only updates those columns, or a options hash.
|
|
1525
|
-
#
|
|
1526
1453
|
# Takes the following options:
|
|
1527
1454
|
#
|
|
1528
1455
|
# :changed :: save all changed columns, instead of all columns or the columns given
|
|
@@ -1537,12 +1464,9 @@ module Sequel
|
|
|
1537
1464
|
def save(opts=OPTS)
|
|
1538
1465
|
raise Sequel::Error, "can't save frozen object" if frozen?
|
|
1539
1466
|
set_server(opts[:server]) if opts[:server]
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
raise(ValidationFailed.new(self)) if raise_on_failure?(opts)
|
|
1544
|
-
return
|
|
1545
|
-
end
|
|
1467
|
+
unless _save_valid?(opts)
|
|
1468
|
+
raise(validation_failed_error) if raise_on_failure?(opts)
|
|
1469
|
+
return
|
|
1546
1470
|
end
|
|
1547
1471
|
checked_save_failure(opts){checked_transaction(opts){_save(opts)}}
|
|
1548
1472
|
end
|
|
@@ -1565,22 +1489,12 @@ module Sequel
|
|
|
1565
1489
|
# a setter method (or ignoring it if <tt>strict_param_setting = false</tt>).
|
|
1566
1490
|
# Does not save the record.
|
|
1567
1491
|
#
|
|
1568
|
-
# artist.set(:
|
|
1492
|
+
# artist.set(name: 'Jim')
|
|
1569
1493
|
# artist.name # => 'Jim'
|
|
1570
1494
|
def set(hash)
|
|
1571
1495
|
set_restricted(hash, :default)
|
|
1572
1496
|
end
|
|
1573
1497
|
|
|
1574
|
-
# Set all values using the entries in the hash, ignoring any setting of
|
|
1575
|
-
# allowed_columns in the model.
|
|
1576
|
-
#
|
|
1577
|
-
# Artist.set_allowed_columns(:num_albums)
|
|
1578
|
-
# artist.set_all(:name=>'Jim')
|
|
1579
|
-
# artist.name # => 'Jim'
|
|
1580
|
-
def set_all(hash)
|
|
1581
|
-
set_restricted(hash, :all)
|
|
1582
|
-
end
|
|
1583
|
-
|
|
1584
1498
|
# For each of the fields in the given array +fields+, call the setter
|
|
1585
1499
|
# method with the value of that +hash+ entry for the field. Returns self.
|
|
1586
1500
|
#
|
|
@@ -1593,43 +1507,36 @@ module Sequel
|
|
|
1593
1507
|
#
|
|
1594
1508
|
# Examples:
|
|
1595
1509
|
#
|
|
1596
|
-
# artist.set_fields({:
|
|
1510
|
+
# artist.set_fields({name: 'Jim'}, [:name])
|
|
1597
1511
|
# artist.name # => 'Jim'
|
|
1598
1512
|
#
|
|
1599
|
-
# artist.set_fields({:
|
|
1513
|
+
# artist.set_fields({hometown: 'LA'}, [:name])
|
|
1600
1514
|
# artist.name # => nil
|
|
1601
1515
|
# artist.hometown # => 'Sac'
|
|
1602
1516
|
#
|
|
1603
1517
|
# artist.name # => 'Jim'
|
|
1604
|
-
# artist.set_fields({}, [:name], :
|
|
1518
|
+
# artist.set_fields({}, [:name], missing: :skip)
|
|
1605
1519
|
# artist.name # => 'Jim'
|
|
1606
1520
|
#
|
|
1607
1521
|
# artist.name # => 'Jim'
|
|
1608
|
-
# artist.set_fields({}, [:name], :
|
|
1522
|
+
# artist.set_fields({}, [:name], missing: :raise)
|
|
1609
1523
|
# # Sequel::Error raised
|
|
1610
1524
|
def set_fields(hash, fields, opts=nil)
|
|
1611
1525
|
opts = if opts
|
|
1612
|
-
|
|
1526
|
+
model.default_set_fields_options.merge(opts)
|
|
1613
1527
|
else
|
|
1614
1528
|
model.default_set_fields_options
|
|
1615
1529
|
end
|
|
1616
1530
|
|
|
1617
|
-
case opts[:missing]
|
|
1618
|
-
when :skip
|
|
1531
|
+
case missing = opts[:missing]
|
|
1532
|
+
when :skip, :raise
|
|
1533
|
+
do_raise = true if missing == :raise
|
|
1619
1534
|
fields.each do |f|
|
|
1620
1535
|
if hash.has_key?(f)
|
|
1621
1536
|
set_column_value("#{f}=", hash[f])
|
|
1622
1537
|
elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
|
|
1623
1538
|
set_column_value("#{sf}=", hash[sf])
|
|
1624
|
-
|
|
1625
|
-
end
|
|
1626
|
-
when :raise
|
|
1627
|
-
fields.each do |f|
|
|
1628
|
-
if hash.has_key?(f)
|
|
1629
|
-
set_column_value("#{f}=", hash[f])
|
|
1630
|
-
elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
|
|
1631
|
-
set_column_value("#{sf}=", hash[sf])
|
|
1632
|
-
else
|
|
1539
|
+
elsif do_raise
|
|
1633
1540
|
raise(Sequel::Error, "missing field in hash: #{f.inspect} not in #{hash.inspect}")
|
|
1634
1541
|
end
|
|
1635
1542
|
end
|
|
@@ -1639,31 +1546,28 @@ module Sequel
|
|
|
1639
1546
|
self
|
|
1640
1547
|
end
|
|
1641
1548
|
|
|
1642
|
-
# Set the values using the entries in the hash, only if the key
|
|
1643
|
-
# is included in only. It may be a better idea to use +set_fields+
|
|
1644
|
-
# instead of this method.
|
|
1645
|
-
#
|
|
1646
|
-
# artist.set_only({:name=>'Jim'}, :name)
|
|
1647
|
-
# artist.name # => 'Jim'
|
|
1648
|
-
#
|
|
1649
|
-
# artist.set_only({:hometown=>'LA'}, :name) # Raise Error
|
|
1650
|
-
def set_only(hash, *only)
|
|
1651
|
-
set_restricted(hash, only.flatten)
|
|
1652
|
-
end
|
|
1653
|
-
|
|
1654
1549
|
# Set the shard that this object is tied to. Returns self.
|
|
1655
1550
|
def set_server(s)
|
|
1656
1551
|
@server = s
|
|
1657
|
-
@this
|
|
1552
|
+
@this = @this.server(s) if @this
|
|
1658
1553
|
self
|
|
1659
1554
|
end
|
|
1660
1555
|
|
|
1661
1556
|
# Clear the setter_methods cache when a method is added
|
|
1662
1557
|
def singleton_method_added(meth)
|
|
1663
|
-
@singleton_setter_added = true if meth.to_s
|
|
1558
|
+
@singleton_setter_added = true if meth.to_s.end_with?('=')
|
|
1664
1559
|
super
|
|
1665
1560
|
end
|
|
1666
1561
|
|
|
1562
|
+
# Skip all validation of the object on the next call to #save,
|
|
1563
|
+
# including the running of validation hooks. This is designed for
|
|
1564
|
+
# and should only be used in cases where #valid? is called before
|
|
1565
|
+
# saving and the <tt>validate: false</tt> option cannot be passed to
|
|
1566
|
+
# #save.
|
|
1567
|
+
def skip_validation_on_next_save!
|
|
1568
|
+
@skip_validation_on_next_save = true
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1667
1571
|
# Returns (naked) dataset that should return only this instance.
|
|
1668
1572
|
#
|
|
1669
1573
|
# Artist[1].this
|
|
@@ -1671,57 +1575,29 @@ module Sequel
|
|
|
1671
1575
|
def this
|
|
1672
1576
|
return @this if @this
|
|
1673
1577
|
raise Error, "No dataset for model #{model}" unless ds = model.instance_dataset
|
|
1674
|
-
|
|
1675
|
-
cond = if ds.joined_dataset?
|
|
1676
|
-
qualified_pk_hash
|
|
1677
|
-
else
|
|
1678
|
-
pk_hash
|
|
1679
|
-
end
|
|
1680
|
-
|
|
1681
|
-
@this = use_server(ds.where(cond))
|
|
1578
|
+
@this = use_server(ds.where(pk_hash))
|
|
1682
1579
|
end
|
|
1683
1580
|
|
|
1684
1581
|
# Runs #set with the passed hash and then runs save_changes.
|
|
1685
1582
|
#
|
|
1686
|
-
# artist.update(:
|
|
1583
|
+
# artist.update(name: 'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1687
1584
|
def update(hash)
|
|
1688
1585
|
update_restricted(hash, :default)
|
|
1689
1586
|
end
|
|
1690
1587
|
|
|
1691
|
-
# Update
|
|
1692
|
-
#
|
|
1693
|
-
#
|
|
1694
|
-
# Artist.set_allowed_columns(:num_albums)
|
|
1695
|
-
# artist.update_all(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1696
|
-
def update_all(hash)
|
|
1697
|
-
update_restricted(hash, :all)
|
|
1698
|
-
end
|
|
1699
|
-
|
|
1700
|
-
# Update the instances values by calling +set_fields+ with the arguments, then
|
|
1701
|
-
# saves any changes to the record. Returns self.
|
|
1588
|
+
# Update the instance's values by calling set_fields with the arguments, then
|
|
1589
|
+
# calls save_changes.
|
|
1702
1590
|
#
|
|
1703
|
-
# artist.update_fields({:
|
|
1591
|
+
# artist.update_fields({name: 'Jim'}, [:name])
|
|
1704
1592
|
# # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1705
1593
|
#
|
|
1706
|
-
# artist.update_fields({:
|
|
1594
|
+
# artist.update_fields({hometown: 'LA'}, [:name])
|
|
1707
1595
|
# # UPDATE artists SET name = NULL WHERE (id = 1)
|
|
1708
1596
|
def update_fields(hash, fields, opts=nil)
|
|
1709
1597
|
set_fields(hash, fields, opts)
|
|
1710
1598
|
save_changes
|
|
1711
1599
|
end
|
|
1712
1600
|
|
|
1713
|
-
# Update the values using the entries in the hash, only if the key
|
|
1714
|
-
# is included in only. It may be a better idea to use +update_fields+
|
|
1715
|
-
# instead of this method.
|
|
1716
|
-
#
|
|
1717
|
-
# artist.update_only({:name=>'Jim'}, :name)
|
|
1718
|
-
# # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
1719
|
-
#
|
|
1720
|
-
# artist.update_only({:hometown=>'LA'}, :name) # Raise Error
|
|
1721
|
-
def update_only(hash, *only)
|
|
1722
|
-
update_restricted(hash, only.flatten)
|
|
1723
|
-
end
|
|
1724
|
-
|
|
1725
1601
|
# Validates the object. If the object is invalid, errors should be added
|
|
1726
1602
|
# to the errors attribute. By default, does nothing, as all models
|
|
1727
1603
|
# are valid by default. See the {"Model Validations" guide}[rdoc-ref:doc/validations.rdoc].
|
|
@@ -1733,25 +1609,37 @@ module Sequel
|
|
|
1733
1609
|
|
|
1734
1610
|
# Validates the object and returns true if no errors are reported.
|
|
1735
1611
|
#
|
|
1736
|
-
# artist(:
|
|
1737
|
-
# artist(:
|
|
1612
|
+
# artist.set(name: 'Valid').valid? # => true
|
|
1613
|
+
# artist.set(name: 'Invalid').valid? # => false
|
|
1738
1614
|
# artist.errors.full_messages # => ['name cannot be Invalid']
|
|
1739
1615
|
def valid?(opts = OPTS)
|
|
1740
|
-
|
|
1741
|
-
|
|
1616
|
+
begin
|
|
1617
|
+
_valid?(opts)
|
|
1618
|
+
rescue HookFailed
|
|
1619
|
+
false
|
|
1620
|
+
end
|
|
1742
1621
|
end
|
|
1743
1622
|
|
|
1744
1623
|
private
|
|
1745
1624
|
|
|
1746
|
-
#
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1625
|
+
# Add a column as a changed column.
|
|
1626
|
+
def _add_changed_column(column)
|
|
1627
|
+
cc = _changed_columns
|
|
1628
|
+
cc << column unless cc.include?(column)
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
# Internal changed_columns method that just returns stored array.
|
|
1632
|
+
def _changed_columns
|
|
1633
|
+
@changed_columns ||= []
|
|
1753
1634
|
end
|
|
1754
1635
|
|
|
1636
|
+
# Clear the changed columns. Reason is the reason for clearing
|
|
1637
|
+
# the columns, and should be one of: :initialize, :refresh, :create
|
|
1638
|
+
# or :update.
|
|
1639
|
+
def _clear_changed_columns(_reason)
|
|
1640
|
+
_changed_columns.clear
|
|
1641
|
+
end
|
|
1642
|
+
|
|
1755
1643
|
# Do the deletion of the object's dataset, and check that the row
|
|
1756
1644
|
# was actually deleted.
|
|
1757
1645
|
def _delete
|
|
@@ -1760,7 +1648,7 @@ module Sequel
|
|
|
1760
1648
|
n
|
|
1761
1649
|
end
|
|
1762
1650
|
|
|
1763
|
-
# The dataset to use when deleting the object.
|
|
1651
|
+
# The dataset to use when deleting the object. The same as the object's
|
|
1764
1652
|
# dataset by default.
|
|
1765
1653
|
def _delete_dataset
|
|
1766
1654
|
this
|
|
@@ -1782,18 +1670,14 @@ module Sequel
|
|
|
1782
1670
|
# Internal destroy method, separted from destroy to
|
|
1783
1671
|
# allow running inside a transaction
|
|
1784
1672
|
def _destroy(opts)
|
|
1785
|
-
sh = {:server=>this_server}
|
|
1786
|
-
db.after_rollback(sh){after_destroy_rollback} if uacr = use_after_commit_rollback
|
|
1787
1673
|
called = false
|
|
1788
1674
|
around_destroy do
|
|
1789
1675
|
called = true
|
|
1790
|
-
|
|
1676
|
+
before_destroy
|
|
1791
1677
|
_destroy_delete
|
|
1792
1678
|
after_destroy
|
|
1793
|
-
true
|
|
1794
1679
|
end
|
|
1795
1680
|
raise_hook_failure(:around_destroy) unless called
|
|
1796
|
-
db.after_commit(sh){after_destroy_commit} if uacr
|
|
1797
1681
|
self
|
|
1798
1682
|
end
|
|
1799
1683
|
|
|
@@ -1808,8 +1692,8 @@ module Sequel
|
|
|
1808
1692
|
# the record should be refreshed from the database.
|
|
1809
1693
|
def _insert
|
|
1810
1694
|
ds = _insert_dataset
|
|
1811
|
-
if _use_insert_select?(ds) && (h = _insert_select_raw(ds))
|
|
1812
|
-
_save_set_values(h)
|
|
1695
|
+
if _use_insert_select?(ds) && !(h = _insert_select_raw(ds)).nil?
|
|
1696
|
+
_save_set_values(h) if h
|
|
1813
1697
|
nil
|
|
1814
1698
|
else
|
|
1815
1699
|
iid = _insert_raw(ds)
|
|
@@ -1830,27 +1714,38 @@ module Sequel
|
|
|
1830
1714
|
|
|
1831
1715
|
# Insert into the given dataset and return the primary key created (if any).
|
|
1832
1716
|
def _insert_raw(ds)
|
|
1833
|
-
ds.insert(
|
|
1717
|
+
ds.insert(_insert_values)
|
|
1834
1718
|
end
|
|
1835
1719
|
|
|
1836
1720
|
# Insert into the given dataset and return the hash of column values.
|
|
1837
1721
|
def _insert_select_raw(ds)
|
|
1838
|
-
ds.insert_select(
|
|
1722
|
+
ds.insert_select(_insert_values)
|
|
1839
1723
|
end
|
|
1724
|
+
|
|
1725
|
+
# The values hash to use when inserting a new record.
|
|
1726
|
+
alias _insert_values values
|
|
1727
|
+
private :_insert_values
|
|
1840
1728
|
|
|
1841
1729
|
# Refresh using a particular dataset, used inside save to make sure the same server
|
|
1842
1730
|
# is used for reading newly inserted values from the database
|
|
1843
1731
|
def _refresh(dataset)
|
|
1844
|
-
_refresh_set_values(_refresh_get(dataset) || raise(
|
|
1845
|
-
|
|
1732
|
+
_refresh_set_values(_refresh_get(dataset) || raise(NoExistingObject, "Record not found"))
|
|
1733
|
+
_clear_changed_columns(:refresh)
|
|
1846
1734
|
end
|
|
1847
1735
|
|
|
1848
1736
|
# Get the row of column data from the database.
|
|
1849
1737
|
def _refresh_get(dataset)
|
|
1850
|
-
dataset.
|
|
1738
|
+
if (sql = model.fast_pk_lookup_sql) && !dataset.opts[:lock]
|
|
1739
|
+
sql = sql.dup
|
|
1740
|
+
ds = use_server(dataset)
|
|
1741
|
+
ds.literal_append(sql, pk)
|
|
1742
|
+
ds.with_sql_first(sql)
|
|
1743
|
+
else
|
|
1744
|
+
dataset.first
|
|
1745
|
+
end
|
|
1851
1746
|
end
|
|
1852
1747
|
|
|
1853
|
-
# Set the
|
|
1748
|
+
# Set the values to the given hash after refreshing.
|
|
1854
1749
|
def _refresh_set_values(h)
|
|
1855
1750
|
@values = h
|
|
1856
1751
|
end
|
|
@@ -1858,24 +1753,22 @@ module Sequel
|
|
|
1858
1753
|
# Internal version of save, split from save to allow running inside
|
|
1859
1754
|
# it's own transaction.
|
|
1860
1755
|
def _save(opts)
|
|
1861
|
-
sh = {:server=>this_server}
|
|
1862
|
-
db.after_rollback(sh){after_rollback} if uacr = use_after_commit_rollback
|
|
1863
|
-
was_new = false
|
|
1864
1756
|
pk = nil
|
|
1865
1757
|
called_save = false
|
|
1866
1758
|
called_cu = false
|
|
1867
1759
|
around_save do
|
|
1868
1760
|
called_save = true
|
|
1869
|
-
|
|
1761
|
+
before_save
|
|
1762
|
+
|
|
1870
1763
|
if new?
|
|
1871
|
-
was_new = true
|
|
1872
1764
|
around_create do
|
|
1873
1765
|
called_cu = true
|
|
1874
|
-
|
|
1766
|
+
before_create
|
|
1875
1767
|
pk = _insert
|
|
1876
1768
|
@this = nil
|
|
1877
1769
|
@new = false
|
|
1878
|
-
@
|
|
1770
|
+
@modified = false
|
|
1771
|
+
pk ? _save_refresh : _clear_changed_columns(:create)
|
|
1879
1772
|
after_create
|
|
1880
1773
|
true
|
|
1881
1774
|
end
|
|
@@ -1883,22 +1776,23 @@ module Sequel
|
|
|
1883
1776
|
else
|
|
1884
1777
|
around_update do
|
|
1885
1778
|
called_cu = true
|
|
1886
|
-
|
|
1779
|
+
before_update
|
|
1887
1780
|
columns = opts[:columns]
|
|
1888
1781
|
if columns.nil?
|
|
1889
|
-
|
|
1890
|
-
|
|
1782
|
+
columns_updated = if opts[:changed]
|
|
1783
|
+
_save_update_changed_colums_hash
|
|
1891
1784
|
else
|
|
1892
1785
|
_save_update_all_columns_hash
|
|
1893
1786
|
end
|
|
1894
|
-
|
|
1787
|
+
_clear_changed_columns(:update)
|
|
1895
1788
|
else # update only the specified columns
|
|
1896
1789
|
columns = Array(columns)
|
|
1897
|
-
|
|
1898
|
-
|
|
1790
|
+
columns_updated = @values.reject{|k, v| !columns.include?(k)}
|
|
1791
|
+
_changed_columns.reject!{|c| columns.include?(c)}
|
|
1899
1792
|
end
|
|
1900
|
-
_update_columns(
|
|
1793
|
+
_update_columns(columns_updated)
|
|
1901
1794
|
@this = nil
|
|
1795
|
+
@modified = false
|
|
1902
1796
|
after_update
|
|
1903
1797
|
true
|
|
1904
1798
|
end
|
|
@@ -1908,14 +1802,6 @@ module Sequel
|
|
|
1908
1802
|
true
|
|
1909
1803
|
end
|
|
1910
1804
|
raise_hook_failure(:around_save) unless called_save
|
|
1911
|
-
if was_new
|
|
1912
|
-
@was_new = nil
|
|
1913
|
-
pk ? _save_refresh : changed_columns.clear
|
|
1914
|
-
else
|
|
1915
|
-
@columns_updated = nil
|
|
1916
|
-
end
|
|
1917
|
-
@modified = false
|
|
1918
|
-
db.after_commit(sh){after_commit} if uacr
|
|
1919
1805
|
self
|
|
1920
1806
|
end
|
|
1921
1807
|
|
|
@@ -1923,8 +1809,8 @@ module Sequel
|
|
|
1923
1809
|
# default values of all columns. Separated from _save so it
|
|
1924
1810
|
# can be overridden to avoid the refresh.
|
|
1925
1811
|
def _save_refresh
|
|
1926
|
-
_save_set_values(_refresh_get(this.server?(:default)) || raise(
|
|
1927
|
-
|
|
1812
|
+
_save_set_values(_refresh_get(this.server?(:default)) || raise(NoExistingObject, "Record not found"))
|
|
1813
|
+
_clear_changed_columns(:create)
|
|
1928
1814
|
end
|
|
1929
1815
|
|
|
1930
1816
|
# Set values to the provided hash. Called after a create,
|
|
@@ -1941,10 +1827,32 @@ module Sequel
|
|
|
1941
1827
|
# to their existing values.
|
|
1942
1828
|
def _save_update_all_columns_hash
|
|
1943
1829
|
v = Hash[@values]
|
|
1944
|
-
|
|
1830
|
+
cc = changed_columns
|
|
1831
|
+
Array(primary_key).each{|x| v.delete(x) unless cc.include?(x)}
|
|
1945
1832
|
v
|
|
1946
1833
|
end
|
|
1947
1834
|
|
|
1835
|
+
# Return a hash of values used when saving changed columns of an
|
|
1836
|
+
# existing object. Defaults to all of the objects current values
|
|
1837
|
+
# that are recorded as modified.
|
|
1838
|
+
def _save_update_changed_colums_hash
|
|
1839
|
+
cc = changed_columns
|
|
1840
|
+
@values.reject{|k,v| !cc.include?(k)}
|
|
1841
|
+
end
|
|
1842
|
+
|
|
1843
|
+
# Validate the object if validating on save. Skips validation
|
|
1844
|
+
# completely (including validation hooks) if
|
|
1845
|
+
# skip_validation_on_save! has been called on the object,
|
|
1846
|
+
# resetting the flag so that future saves will validate.
|
|
1847
|
+
def _save_valid?(opts)
|
|
1848
|
+
if @skip_validation_on_next_save
|
|
1849
|
+
@skip_validation_on_next_save = false
|
|
1850
|
+
return true
|
|
1851
|
+
end
|
|
1852
|
+
|
|
1853
|
+
checked_save_failure(opts){_valid?(opts)}
|
|
1854
|
+
end
|
|
1855
|
+
|
|
1948
1856
|
# Call _update with the given columns, if any are present.
|
|
1949
1857
|
# Plugins can override this method in order to update with
|
|
1950
1858
|
# additional columns, even when the column hash is initially empty.
|
|
@@ -1976,38 +1884,25 @@ module Sequel
|
|
|
1976
1884
|
(!ds.opts[:select] || ds.opts[:returning]) && ds.supports_insert_select?
|
|
1977
1885
|
end
|
|
1978
1886
|
|
|
1979
|
-
# Internal validation method
|
|
1980
|
-
|
|
1981
|
-
# +false+, +false+ will be returned instead.
|
|
1982
|
-
def _valid?(raise_errors, opts)
|
|
1887
|
+
# Internal validation method, running validation hooks.
|
|
1888
|
+
def _valid?(opts)
|
|
1983
1889
|
return errors.empty? if frozen?
|
|
1984
1890
|
errors.clear
|
|
1985
1891
|
called = false
|
|
1986
|
-
|
|
1892
|
+
skip_validate = opts[:validate] == false
|
|
1987
1893
|
around_validation do
|
|
1988
1894
|
called = true
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
else
|
|
1993
|
-
error = true
|
|
1994
|
-
end
|
|
1995
|
-
false
|
|
1996
|
-
else
|
|
1997
|
-
validate
|
|
1998
|
-
after_validation
|
|
1999
|
-
errors.empty?
|
|
2000
|
-
end
|
|
1895
|
+
before_validation
|
|
1896
|
+
validate unless skip_validate
|
|
1897
|
+
after_validation
|
|
2001
1898
|
end
|
|
2002
|
-
|
|
2003
|
-
if
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
else
|
|
2007
|
-
false
|
|
2008
|
-
end
|
|
2009
|
-
else
|
|
1899
|
+
|
|
1900
|
+
return true if skip_validate
|
|
1901
|
+
|
|
1902
|
+
if called
|
|
2010
1903
|
errors.empty?
|
|
1904
|
+
else
|
|
1905
|
+
raise_hook_failure(:around_validation)
|
|
2011
1906
|
end
|
|
2012
1907
|
end
|
|
2013
1908
|
|
|
@@ -2032,8 +1927,7 @@ module Sequel
|
|
|
2032
1927
|
|
|
2033
1928
|
# Change the value of the column to given value, recording the change.
|
|
2034
1929
|
def change_column_value(column, value)
|
|
2035
|
-
|
|
2036
|
-
cc << column unless cc.include?(column)
|
|
1930
|
+
_add_changed_column(column)
|
|
2037
1931
|
@values[column] = value
|
|
2038
1932
|
end
|
|
2039
1933
|
|
|
@@ -2042,24 +1936,17 @@ module Sequel
|
|
|
2042
1936
|
Errors
|
|
2043
1937
|
end
|
|
2044
1938
|
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
def clone
|
|
2057
|
-
o = dup
|
|
2058
|
-
o.freeze if frozen?
|
|
2059
|
-
o
|
|
2060
|
-
end
|
|
2061
|
-
public :clone
|
|
2062
|
-
# :nocov:
|
|
1939
|
+
# A HookFailed exception for the given message tied to the current instance.
|
|
1940
|
+
def hook_failed_error(msg)
|
|
1941
|
+
HookFailed.new(msg, self)
|
|
1942
|
+
end
|
|
1943
|
+
|
|
1944
|
+
# Clone constructor -- freeze internal data structures if the original's
|
|
1945
|
+
# are frozen.
|
|
1946
|
+
def initialize_clone(other)
|
|
1947
|
+
super
|
|
1948
|
+
freeze if other.frozen?
|
|
1949
|
+
self
|
|
2063
1950
|
end
|
|
2064
1951
|
|
|
2065
1952
|
# Copy constructor -- Duplicate internal data structures.
|
|
@@ -2068,7 +1955,6 @@ module Sequel
|
|
|
2068
1955
|
@values = Hash[@values]
|
|
2069
1956
|
@changed_columns = @changed_columns.dup if @changed_columns
|
|
2070
1957
|
@errors = @errors.dup if @errors
|
|
2071
|
-
@this = @this.dup if @this
|
|
2072
1958
|
self
|
|
2073
1959
|
end
|
|
2074
1960
|
|
|
@@ -2104,9 +1990,9 @@ module Sequel
|
|
|
2104
1990
|
"a hook failed"
|
|
2105
1991
|
end
|
|
2106
1992
|
|
|
2107
|
-
raise
|
|
1993
|
+
raise hook_failed_error(msg)
|
|
2108
1994
|
end
|
|
2109
|
-
|
|
1995
|
+
|
|
2110
1996
|
# Get the ruby class or classes related to the given column's type.
|
|
2111
1997
|
def schema_type_class(column)
|
|
2112
1998
|
if (sch = db_schema[column]) && (type = sch[:type])
|
|
@@ -2147,19 +2033,13 @@ module Sequel
|
|
|
2147
2033
|
# :all :: Allow setting all setters, except those specifically restricted (such as ==).
|
|
2148
2034
|
# Array :: Only allow setting of columns in the given array.
|
|
2149
2035
|
def setter_methods(type)
|
|
2150
|
-
if type == :default
|
|
2151
|
-
|
|
2152
|
-
return model.setter_methods
|
|
2153
|
-
end
|
|
2036
|
+
if type == :default && !@singleton_setter_added
|
|
2037
|
+
return model.setter_methods
|
|
2154
2038
|
end
|
|
2155
2039
|
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
meths = methods.collect(&:to_s).grep(SETTER_METHOD_REGEXP) - RESTRICTED_SETTER_METHODS
|
|
2160
|
-
meths -= Array(primary_key).map{|x| "#{x}="} if type != :all && primary_key && model.restrict_primary_key?
|
|
2161
|
-
meths
|
|
2162
|
-
end
|
|
2040
|
+
meths = methods.map(&:to_s).select{|l| l.end_with?('=')} - RESTRICTED_SETTER_METHODS
|
|
2041
|
+
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && model.restrict_primary_key?
|
|
2042
|
+
meths
|
|
2163
2043
|
end
|
|
2164
2044
|
|
|
2165
2045
|
# The server/shard that the model object's dataset uses, or :default if the
|
|
@@ -2205,22 +2085,28 @@ module Sequel
|
|
|
2205
2085
|
def use_transaction?(opts = OPTS)
|
|
2206
2086
|
opts.fetch(:transaction, use_transactions)
|
|
2207
2087
|
end
|
|
2088
|
+
|
|
2089
|
+
# An ValidationFailed exception instance to raise for this instance.
|
|
2090
|
+
def validation_failed_error
|
|
2091
|
+
ValidationFailed.new(self)
|
|
2092
|
+
end
|
|
2208
2093
|
end
|
|
2209
2094
|
|
|
2210
|
-
#
|
|
2211
|
-
# the call to set_dataset.
|
|
2095
|
+
# DatasetMethods contains methods that all model datasets have.
|
|
2212
2096
|
module DatasetMethods
|
|
2213
2097
|
# The model class associated with this dataset
|
|
2214
2098
|
#
|
|
2215
2099
|
# Artist.dataset.model # => Artist
|
|
2216
|
-
|
|
2100
|
+
def model
|
|
2101
|
+
@opts[:model]
|
|
2102
|
+
end
|
|
2217
2103
|
|
|
2218
2104
|
# Assume if a single integer is given that it is a lookup by primary
|
|
2219
2105
|
# key, and call with_pk with the argument.
|
|
2220
2106
|
#
|
|
2221
2107
|
# Artist.dataset[1] # SELECT * FROM artists WHERE (id = 1) LIMIT 1
|
|
2222
2108
|
def [](*args)
|
|
2223
|
-
if args.length == 1 && (i = args
|
|
2109
|
+
if args.length == 1 && (i = args[0]) && i.is_a?(Integer)
|
|
2224
2110
|
with_pk(i)
|
|
2225
2111
|
else
|
|
2226
2112
|
super
|
|
@@ -2241,58 +2127,14 @@ module Sequel
|
|
|
2241
2127
|
model.use_transactions ? @db.transaction(:server=>opts[:server], &pr) : pr.call
|
|
2242
2128
|
end
|
|
2243
2129
|
|
|
2244
|
-
# Allow Sequel::Model classes to be used as dataset arguments when graphing:
|
|
2245
|
-
#
|
|
2246
|
-
# Artist.graph(Album, :artist_id=>id)
|
|
2247
|
-
# # SELECT artists.id, artists.name, albums.id AS albums_id, albums.artist_id, albums.name AS albums_name
|
|
2248
|
-
# # FROM artists LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
|
2249
|
-
def graph(table, *args, &block)
|
|
2250
|
-
if table.is_a?(Class) && table < Sequel::Model
|
|
2251
|
-
super(table.dataset, *args, &block)
|
|
2252
|
-
else
|
|
2253
|
-
super
|
|
2254
|
-
end
|
|
2255
|
-
end
|
|
2256
|
-
|
|
2257
|
-
# Handle Sequel::Model instances when inserting, using the model instance's
|
|
2258
|
-
# values for the insert, unless the model instance can be used directly in
|
|
2259
|
-
# SQL.
|
|
2260
|
-
#
|
|
2261
|
-
# Album.insert(Album.load(:name=>'A'))
|
|
2262
|
-
# # INSERT INTO albums (name) VALUES ('A')
|
|
2263
|
-
def insert_sql(*values)
|
|
2264
|
-
if values.size == 1 && (v = values.at(0)).is_a?(Sequel::Model) && !v.respond_to?(:sql_literal_append)
|
|
2265
|
-
super(v.to_hash)
|
|
2266
|
-
else
|
|
2267
|
-
super
|
|
2268
|
-
end
|
|
2269
|
-
end
|
|
2270
|
-
|
|
2271
|
-
# Allow Sequel::Model classes to be used as table name arguments in dataset
|
|
2272
|
-
# join methods:
|
|
2273
|
-
#
|
|
2274
|
-
# Artist.join(Album, :artist_id=>id)
|
|
2275
|
-
# # SELECT * FROM artists INNER JOIN albums ON (albums.artist_id = artists.id)
|
|
2276
|
-
def join_table(type, table, *args, &block)
|
|
2277
|
-
if table.is_a?(Class) && table < Sequel::Model
|
|
2278
|
-
if table.dataset.simple_select_all?
|
|
2279
|
-
super(type, table.table_name, *args, &block)
|
|
2280
|
-
else
|
|
2281
|
-
super(type, table.dataset, *args, &block)
|
|
2282
|
-
end
|
|
2283
|
-
else
|
|
2284
|
-
super
|
|
2285
|
-
end
|
|
2286
|
-
end
|
|
2287
|
-
|
|
2288
2130
|
# If there is no order already defined on this dataset, order it by
|
|
2289
2131
|
# the primary key and call last.
|
|
2290
2132
|
#
|
|
2291
2133
|
# Album.last
|
|
2292
2134
|
# # SELECT * FROM albums ORDER BY id DESC LIMIT 1
|
|
2293
2135
|
def last(*a, &block)
|
|
2294
|
-
if
|
|
2295
|
-
|
|
2136
|
+
if ds = _primary_key_order
|
|
2137
|
+
ds.last(*a, &block)
|
|
2296
2138
|
else
|
|
2297
2139
|
super
|
|
2298
2140
|
end
|
|
@@ -2307,30 +2149,35 @@ module Sequel
|
|
|
2307
2149
|
# # SELECT * FROM albums ORDER BY id LIMIT 1000 OFFSET 2000
|
|
2308
2150
|
# # ...
|
|
2309
2151
|
def paged_each(*a, &block)
|
|
2310
|
-
if
|
|
2311
|
-
|
|
2152
|
+
if ds = _primary_key_order
|
|
2153
|
+
ds.paged_each(*a, &block)
|
|
2312
2154
|
else
|
|
2313
2155
|
super
|
|
2314
2156
|
end
|
|
2315
2157
|
end
|
|
2316
2158
|
|
|
2317
|
-
# This allows you to call +
|
|
2159
|
+
# This allows you to call +as_hash+ without any arguments, which will
|
|
2318
2160
|
# result in a hash with the primary key value being the key and the
|
|
2319
2161
|
# model object being the value.
|
|
2320
2162
|
#
|
|
2321
|
-
# Artist.dataset.
|
|
2163
|
+
# Artist.dataset.as_hash # SELECT * FROM artists
|
|
2322
2164
|
# # => {1=>#<Artist {:id=>1, ...}>,
|
|
2323
2165
|
# # 2=>#<Artist {:id=>2, ...}>,
|
|
2324
2166
|
# # ...}
|
|
2325
|
-
def
|
|
2167
|
+
def as_hash(key_column=nil, value_column=nil, opts=OPTS)
|
|
2326
2168
|
if key_column
|
|
2327
2169
|
super
|
|
2328
2170
|
else
|
|
2329
2171
|
raise(Sequel::Error, "No primary key for model") unless model && (pk = model.primary_key)
|
|
2330
|
-
super(pk, value_column)
|
|
2172
|
+
super(pk, value_column, opts)
|
|
2331
2173
|
end
|
|
2332
2174
|
end
|
|
2333
2175
|
|
|
2176
|
+
# Alias of as_hash for backwards compatibility.
|
|
2177
|
+
def to_hash(*a)
|
|
2178
|
+
as_hash(*a)
|
|
2179
|
+
end
|
|
2180
|
+
|
|
2334
2181
|
# Given a primary key value, return the first record in the dataset with that primary key
|
|
2335
2182
|
# value. If no records matches, returns nil.
|
|
2336
2183
|
#
|
|
@@ -2342,7 +2189,11 @@ module Sequel
|
|
|
2342
2189
|
# Artist.dataset.with_pk([1, 2])
|
|
2343
2190
|
# # SELECT * FROM artists WHERE ((artists.id1 = 1) AND (artists.id2 = 2)) LIMIT 1
|
|
2344
2191
|
def with_pk(pk)
|
|
2345
|
-
|
|
2192
|
+
if pk && (loader = _with_pk_loader)
|
|
2193
|
+
loader.first(*pk)
|
|
2194
|
+
else
|
|
2195
|
+
first(model.qualified_primary_key_hash(pk))
|
|
2196
|
+
end
|
|
2346
2197
|
end
|
|
2347
2198
|
|
|
2348
2199
|
# Same as with_pk, but raises NoMatchingRow instead of returning nil if no
|
|
@@ -2350,10 +2201,47 @@ module Sequel
|
|
|
2350
2201
|
def with_pk!(pk)
|
|
2351
2202
|
with_pk(pk) || raise(NoMatchingRow.new(self))
|
|
2352
2203
|
end
|
|
2204
|
+
|
|
2205
|
+
private
|
|
2206
|
+
|
|
2207
|
+
# If the dataset is not already ordered, and the model has a primary key,
|
|
2208
|
+
# return a clone ordered by the primary key.
|
|
2209
|
+
def _primary_key_order
|
|
2210
|
+
if @opts[:order].nil? && model && (pk = model.primary_key)
|
|
2211
|
+
cached_dataset(:_pk_order_ds){order(*pk)}
|
|
2212
|
+
end
|
|
2213
|
+
end
|
|
2214
|
+
|
|
2215
|
+
# A cached placeholder literalizer, if one exists for the current dataset.
|
|
2216
|
+
def _with_pk_loader
|
|
2217
|
+
cached_placeholder_literalizer(:_with_pk_loader) do |pl|
|
|
2218
|
+
table = model.table_name
|
|
2219
|
+
cond = case primary_key = model.primary_key
|
|
2220
|
+
when Array
|
|
2221
|
+
primary_key.map{|key| [SQL::QualifiedIdentifier.new(table, key), pl.arg]}
|
|
2222
|
+
when Symbol
|
|
2223
|
+
{SQL::QualifiedIdentifier.new(table, primary_key)=>pl.arg}
|
|
2224
|
+
else
|
|
2225
|
+
raise(Error, "#{model} does not have a primary key")
|
|
2226
|
+
end
|
|
2227
|
+
|
|
2228
|
+
where(cond).limit(1)
|
|
2229
|
+
end
|
|
2230
|
+
end
|
|
2231
|
+
|
|
2232
|
+
def non_sql_option?(key)
|
|
2233
|
+
super || key == :model
|
|
2234
|
+
end
|
|
2353
2235
|
end
|
|
2354
2236
|
|
|
2355
2237
|
extend ClassMethods
|
|
2356
2238
|
plugin self
|
|
2357
|
-
|
|
2239
|
+
|
|
2240
|
+
singleton_class.send(:undef_method, :dup, :clone, :initialize_copy)
|
|
2241
|
+
# :nocov:
|
|
2242
|
+
if RUBY_VERSION >= '1.9.3'
|
|
2243
|
+
# :nocov:
|
|
2244
|
+
singleton_class.send(:undef_method, :initialize_clone, :initialize_dup)
|
|
2245
|
+
end
|
|
2358
2246
|
end
|
|
2359
2247
|
end
|