sequel 4.36.0 → 5.61.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 +548 -5749
- data/MIT-LICENSE +1 -1
- data/README.rdoc +265 -159
- data/bin/sequel +34 -12
- data/doc/advanced_associations.rdoc +228 -187
- data/doc/association_basics.rdoc +281 -291
- data/doc/bin_sequel.rdoc +5 -3
- data/doc/cheat_sheet.rdoc +86 -51
- data/doc/code_order.rdoc +25 -19
- 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/fork_safety.rdoc +84 -0
- data/doc/mass_assignment.rdoc +74 -31
- data/doc/migration.rdoc +59 -51
- 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 +58 -68
- data/doc/opening_databases.rdoc +85 -95
- data/doc/postgresql.rdoc +263 -38
- data/doc/prepared_statements.rdoc +29 -24
- data/doc/querying.rdoc +189 -167
- 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.38.0.txt +28 -0
- data/doc/release_notes/5.39.0.txt +19 -0
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/release_notes/5.40.0.txt +40 -0
- data/doc/release_notes/5.41.0.txt +25 -0
- data/doc/release_notes/5.42.0.txt +136 -0
- data/doc/release_notes/5.43.0.txt +98 -0
- data/doc/release_notes/5.44.0.txt +32 -0
- data/doc/release_notes/5.45.0.txt +34 -0
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.5.0.txt +61 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.6.0.txt +31 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -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 +95 -75
- data/doc/security.rdoc +109 -80
- data/doc/sharding.rdoc +74 -47
- data/doc/sql.rdoc +147 -122
- data/doc/testing.rdoc +43 -20
- data/doc/thread_safety.rdoc +2 -4
- data/doc/transactions.rdoc +97 -18
- data/doc/validations.rdoc +52 -50
- data/doc/virtual_rows.rdoc +90 -109
- data/lib/sequel/adapters/ado/access.rb +15 -17
- data/lib/sequel/adapters/ado/mssql.rb +6 -15
- data/lib/sequel/adapters/ado.rb +150 -20
- data/lib/sequel/adapters/amalgalite.rb +11 -23
- data/lib/sequel/adapters/ibmdb.rb +47 -55
- data/lib/sequel/adapters/jdbc/db2.rb +29 -39
- data/lib/sequel/adapters/jdbc/derby.rb +58 -54
- data/lib/sequel/adapters/jdbc/h2.rb +93 -35
- data/lib/sequel/adapters/jdbc/hsqldb.rb +24 -31
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -10
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -11
- data/lib/sequel/adapters/jdbc/mysql.rb +17 -20
- data/lib/sequel/adapters/jdbc/oracle.rb +22 -18
- data/lib/sequel/adapters/jdbc/postgresql.rb +69 -71
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +11 -23
- data/lib/sequel/adapters/jdbc/sqlite.rb +47 -11
- data/lib/sequel/adapters/jdbc/sqlserver.rb +34 -9
- data/lib/sequel/adapters/jdbc/transactions.rb +22 -38
- data/lib/sequel/adapters/jdbc.rb +145 -130
- data/lib/sequel/adapters/mock.rb +100 -111
- data/lib/sequel/adapters/mysql.rb +114 -122
- data/lib/sequel/adapters/mysql2.rb +147 -63
- data/lib/sequel/adapters/odbc/db2.rb +1 -1
- data/lib/sequel/adapters/odbc/mssql.rb +8 -14
- data/lib/sequel/adapters/odbc/oracle.rb +11 -0
- data/lib/sequel/adapters/odbc.rb +20 -25
- data/lib/sequel/adapters/oracle.rb +50 -56
- data/lib/sequel/adapters/postgres.rb +305 -327
- data/lib/sequel/adapters/postgresql.rb +1 -1
- data/lib/sequel/adapters/shared/access.rb +74 -78
- data/lib/sequel/adapters/shared/db2.rb +118 -71
- data/lib/sequel/adapters/shared/mssql.rb +301 -220
- data/lib/sequel/adapters/shared/mysql.rb +299 -217
- data/lib/sequel/adapters/shared/oracle.rb +226 -65
- data/lib/sequel/adapters/shared/postgres.rb +935 -395
- data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -126
- data/lib/sequel/adapters/shared/sqlite.rb +447 -173
- data/lib/sequel/adapters/sqlanywhere.rb +48 -35
- data/lib/sequel/adapters/sqlite.rb +156 -111
- data/lib/sequel/adapters/tinytds.rb +30 -38
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +3 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -2
- 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 +1 -4
- data/lib/sequel/adapters/utils/stored_procedures.rb +7 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
- data/lib/sequel/ast_transformer.rb +17 -89
- data/lib/sequel/connection_pool/sharded_single.rb +18 -15
- data/lib/sequel/connection_pool/sharded_threaded.rb +130 -111
- data/lib/sequel/connection_pool/single.rb +18 -13
- data/lib/sequel/connection_pool/threaded.rb +121 -120
- data/lib/sequel/connection_pool.rb +48 -29
- data/lib/sequel/core.rb +351 -301
- data/lib/sequel/database/connecting.rb +69 -57
- data/lib/sequel/database/dataset.rb +13 -5
- data/lib/sequel/database/dataset_defaults.rb +18 -102
- data/lib/sequel/database/features.rb +18 -4
- data/lib/sequel/database/logging.rb +12 -11
- data/lib/sequel/database/misc.rb +180 -122
- data/lib/sequel/database/query.rb +47 -27
- data/lib/sequel/database/schema_generator.rb +178 -84
- data/lib/sequel/database/schema_methods.rb +172 -97
- data/lib/sequel/database/transactions.rb +205 -44
- data/lib/sequel/database.rb +17 -2
- data/lib/sequel/dataset/actions.rb +339 -155
- data/lib/sequel/dataset/dataset_module.rb +46 -0
- data/lib/sequel/dataset/features.rb +90 -35
- data/lib/sequel/dataset/graph.rb +80 -58
- data/lib/sequel/dataset/misc.rb +137 -47
- data/lib/sequel/dataset/placeholder_literalizer.rb +63 -25
- data/lib/sequel/dataset/prepared_statements.rb +188 -85
- data/lib/sequel/dataset/query.rb +530 -222
- data/lib/sequel/dataset/sql.rb +590 -368
- data/lib/sequel/dataset.rb +26 -16
- data/lib/sequel/deprecated.rb +12 -2
- data/lib/sequel/exceptions.rb +46 -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 +2 -5
- data/lib/sequel/extensions/any_not_empty.rb +45 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
- data/lib/sequel/extensions/async_thread_pool.rb +438 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/blank.rb +8 -0
- data/lib/sequel/extensions/caller_logging.rb +79 -0
- data/lib/sequel/extensions/columns_introspection.rb +4 -3
- data/lib/sequel/extensions/connection_expiration.rb +20 -10
- data/lib/sequel/extensions/connection_validator.rb +11 -10
- data/lib/sequel/extensions/constant_sql_override.rb +65 -0
- data/lib/sequel/extensions/constraint_validations.rb +62 -39
- data/lib/sequel/extensions/core_extensions.rb +42 -48
- data/lib/sequel/extensions/core_refinements.rb +80 -59
- data/lib/sequel/extensions/current_datetime_timestamp.rb +1 -4
- data/lib/sequel/extensions/date_arithmetic.rb +98 -39
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +41 -0
- data/lib/sequel/extensions/duplicate_columns_handler.rb +21 -14
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
- data/lib/sequel/extensions/escaped_like.rb +100 -0
- data/lib/sequel/extensions/eval_inspect.rb +12 -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 +1 -34
- data/lib/sequel/extensions/graph_each.rb +4 -4
- 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 +13 -5
- data/lib/sequel/extensions/integer64.rb +32 -0
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +17 -8
- data/lib/sequel/extensions/migration.rb +119 -78
- data/lib/sequel/extensions/named_timezones.rb +88 -23
- data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -82
- data/lib/sequel/extensions/null_dataset.rb +8 -8
- data/lib/sequel/extensions/pagination.rb +32 -29
- data/lib/sequel/extensions/pg_array.rb +221 -287
- data/lib/sequel/extensions/pg_array_ops.rb +17 -9
- data/lib/sequel/extensions/pg_enum.rb +63 -23
- data/lib/sequel/extensions/pg_extended_date_support.rb +241 -0
- data/lib/sequel/extensions/pg_hstore.rb +45 -54
- data/lib/sequel/extensions/pg_hstore_ops.rb +58 -6
- data/lib/sequel/extensions/pg_inet.rb +31 -12
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
- data/lib/sequel/extensions/pg_interval.rb +56 -29
- data/lib/sequel/extensions/pg_json.rb +417 -140
- data/lib/sequel/extensions/pg_json_ops.rb +270 -18
- data/lib/sequel/extensions/pg_loose_count.rb +4 -2
- data/lib/sequel/extensions/pg_multirange.rb +372 -0
- data/lib/sequel/extensions/pg_range.rb +131 -191
- data/lib/sequel/extensions/pg_range_ops.rb +42 -13
- data/lib/sequel/extensions/pg_row.rb +48 -81
- data/lib/sequel/extensions/pg_row_ops.rb +33 -14
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
- data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
- data/lib/sequel/extensions/query.rb +9 -7
- data/lib/sequel/extensions/round_timestamps.rb +0 -6
- data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
- data/lib/sequel/extensions/s.rb +60 -0
- data/lib/sequel/extensions/schema_caching.rb +10 -1
- data/lib/sequel/extensions/schema_dumper.rb +71 -48
- data/lib/sequel/extensions/select_remove.rb +4 -4
- data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
- data/lib/sequel/extensions/server_block.rb +51 -27
- data/lib/sequel/extensions/split_array_nil.rb +4 -4
- data/lib/sequel/extensions/sql_comments.rb +119 -7
- data/lib/sequel/extensions/sql_expr.rb +2 -1
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +11 -8
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +55 -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/to_dot.rb +10 -4
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model/associations.rb +1006 -284
- data/lib/sequel/model/base.rb +560 -805
- data/lib/sequel/model/dataset_module.rb +11 -10
- data/lib/sequel/model/default_inflections.rb +1 -1
- data/lib/sequel/model/errors.rb +10 -3
- data/lib/sequel/model/exceptions.rb +8 -10
- data/lib/sequel/model/inflections.rb +7 -20
- data/lib/sequel/model/plugins.rb +114 -0
- data/lib/sequel/model.rb +32 -82
- data/lib/sequel/plugins/active_model.rb +30 -14
- data/lib/sequel/plugins/after_initialize.rb +1 -1
- data/lib/sequel/plugins/association_dependencies.rb +25 -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 +147 -70
- data/lib/sequel/plugins/association_proxies.rb +33 -9
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +95 -28
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/before_after_save.rb +0 -42
- data/lib/sequel/plugins/blacklist_security.rb +21 -12
- data/lib/sequel/plugins/boolean_readers.rb +5 -5
- data/lib/sequel/plugins/boolean_subsets.rb +13 -8
- data/lib/sequel/plugins/caching.rb +25 -16
- data/lib/sequel/plugins/class_table_inheritance.rb +179 -100
- data/lib/sequel/plugins/column_conflicts.rb +16 -3
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/column_select.rb +7 -5
- data/lib/sequel/plugins/columns_updated.rb +42 -0
- data/lib/sequel/plugins/composition.rb +42 -26
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/constraint_validations.rb +20 -14
- data/lib/sequel/plugins/csv_serializer.rb +56 -35
- data/lib/sequel/plugins/dataset_associations.rb +40 -17
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/defaults_setter.rb +65 -10
- data/lib/sequel/plugins/delay_add_association.rb +1 -1
- data/lib/sequel/plugins/dirty.rb +62 -24
- data/lib/sequel/plugins/eager_each.rb +3 -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/enum.rb +124 -0
- data/lib/sequel/plugins/error_splitter.rb +17 -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 +7 -12
- data/lib/sequel/plugins/hook_class_methods.rb +37 -54
- data/lib/sequel/plugins/input_transformer.rb +18 -10
- data/lib/sequel/plugins/insert_conflict.rb +76 -0
- data/lib/sequel/plugins/insert_returning_select.rb +2 -2
- data/lib/sequel/plugins/instance_filters.rb +10 -8
- data/lib/sequel/plugins/instance_hooks.rb +34 -17
- data/lib/sequel/plugins/instance_specific_default.rb +113 -0
- data/lib/sequel/plugins/inverted_subsets.rb +22 -13
- data/lib/sequel/plugins/json_serializer.rb +124 -64
- data/lib/sequel/plugins/lazy_attributes.rb +21 -14
- data/lib/sequel/plugins/list.rb +35 -21
- data/lib/sequel/plugins/many_through_many.rb +134 -21
- data/lib/sequel/plugins/modification_detection.rb +15 -5
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +6 -5
- data/lib/sequel/plugins/nested_attributes.rb +61 -31
- data/lib/sequel/plugins/optimistic_locking.rb +3 -3
- data/lib/sequel/plugins/pg_array_associations.rb +103 -53
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +350 -0
- data/lib/sequel/plugins/pg_row.rb +5 -51
- data/lib/sequel/plugins/prepared_statements.rb +60 -72
- data/lib/sequel/plugins/prepared_statements_safe.rb +9 -4
- data/lib/sequel/plugins/rcte_tree.rb +68 -82
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +43 -46
- data/lib/sequel/plugins/serialization_modification_detection.rb +3 -2
- data/lib/sequel/plugins/sharding.rb +15 -10
- data/lib/sequel/plugins/single_table_inheritance.rb +67 -28
- data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
- data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
- data/lib/sequel/plugins/split_values.rb +11 -6
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +77 -53
- data/lib/sequel/plugins/static_cache_cache.rb +53 -0
- data/lib/sequel/plugins/string_stripper.rb +3 -3
- data/lib/sequel/plugins/subclasses.rb +43 -10
- data/lib/sequel/plugins/subset_conditions.rb +15 -5
- data/lib/sequel/plugins/table_select.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +96 -12
- data/lib/sequel/plugins/throw_failures.rb +110 -0
- data/lib/sequel/plugins/timestamps.rb +20 -8
- data/lib/sequel/plugins/touch.rb +19 -8
- data/lib/sequel/plugins/tree.rb +62 -32
- data/lib/sequel/plugins/typecast_on_load.rb +12 -4
- data/lib/sequel/plugins/unlimited_update.rb +1 -7
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +4 -4
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/plugins/update_refresh.rb +26 -15
- data/lib/sequel/plugins/uuid.rb +7 -11
- data/lib/sequel/plugins/validate_associated.rb +18 -0
- data/lib/sequel/plugins/validation_class_methods.rb +38 -19
- data/lib/sequel/plugins/validation_contexts.rb +49 -0
- data/lib/sequel/plugins/validation_helpers.rb +57 -41
- data/lib/sequel/plugins/whitelist_security.rb +122 -0
- data/lib/sequel/plugins/xml_serializer.rb +30 -31
- data/lib/sequel/sql.rb +471 -331
- data/lib/sequel/timezones.rb +78 -47
- data/lib/sequel/version.rb +7 -2
- data/lib/sequel.rb +1 -1
- metadata +217 -521
- data/Rakefile +0 -164
- data/doc/active_record.rdoc +0 -928
- 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.27.0.txt +0 -78
- data/doc/release_notes/4.28.0.txt +0 -57
- data/doc/release_notes/4.29.0.txt +0 -41
- data/doc/release_notes/4.3.0.txt +0 -40
- data/doc/release_notes/4.30.0.txt +0 -37
- data/doc/release_notes/4.31.0.txt +0 -57
- data/doc/release_notes/4.32.0.txt +0 -132
- data/doc/release_notes/4.33.0.txt +0 -88
- data/doc/release_notes/4.34.0.txt +0 -86
- data/doc/release_notes/4.35.0.txt +0 -130
- data/doc/release_notes/4.36.0.txt +0 -116
- 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 -144
- data/lib/sequel/adapters/do/mysql.rb +0 -66
- data/lib/sequel/adapters/do/postgres.rb +0 -44
- data/lib/sequel/adapters/do/sqlite3.rb +0 -42
- data/lib/sequel/adapters/do.rb +0 -158
- data/lib/sequel/adapters/jdbc/as400.rb +0 -84
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -64
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -36
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -33
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -33
- data/lib/sequel/adapters/odbc/progress.rb +0 -10
- data/lib/sequel/adapters/shared/cubrid.rb +0 -245
- data/lib/sequel/adapters/shared/firebird.rb +0 -247
- data/lib/sequel/adapters/shared/informix.rb +0 -54
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -152
- data/lib/sequel/adapters/shared/progress.rb +0 -40
- data/lib/sequel/adapters/swift/mysql.rb +0 -49
- data/lib/sequel/adapters/swift/postgres.rb +0 -47
- data/lib/sequel/adapters/swift/sqlite.rb +0 -49
- data/lib/sequel/adapters/swift.rb +0 -160
- data/lib/sequel/adapters/utils/pg_types.rb +0 -70
- data/lib/sequel/dataset/mutation.rb +0 -111
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -5
- data/lib/sequel/extensions/filter_having.rb +0 -63
- data/lib/sequel/extensions/hash_aliases.rb +0 -49
- data/lib/sequel/extensions/meta_def.rb +0 -35
- data/lib/sequel/extensions/query_literals.rb +0 -84
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -24
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -122
- data/lib/sequel/extensions/set_overrides.rb +0 -76
- data/lib/sequel/no_core_ext.rb +0 -3
- data/lib/sequel/plugins/association_autoreloading.rb +0 -9
- data/lib/sequel/plugins/identifier_columns.rb +0 -47
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -9
- data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -81
- data/lib/sequel/plugins/prepared_statements_associations.rb +0 -119
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -61
- data/lib/sequel/plugins/schema.rb +0 -82
- data/lib/sequel/plugins/scissors.rb +0 -35
- data/spec/adapter_spec.rb +0 -4
- 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 -733
- data/spec/adapters/mysql_spec.rb +0 -1319
- data/spec/adapters/oracle_spec.rb +0 -313
- data/spec/adapters/postgres_spec.rb +0 -3790
- data/spec/adapters/spec_helper.rb +0 -49
- data/spec/adapters/sqlanywhere_spec.rb +0 -170
- data/spec/adapters/sqlite_spec.rb +0 -688
- data/spec/bin_spec.rb +0 -258
- data/spec/core/connection_pool_spec.rb +0 -1045
- data/spec/core/database_spec.rb +0 -2636
- data/spec/core/dataset_spec.rb +0 -5175
- data/spec/core/deprecated_spec.rb +0 -70
- data/spec/core/expression_filters_spec.rb +0 -1247
- data/spec/core/mock_adapter_spec.rb +0 -464
- 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 -203
- data/spec/core/schema_spec.rb +0 -1676
- 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/core_model_spec.rb +0 -2
- data/spec/core_spec.rb +0 -1
- data/spec/extensions/accessed_columns_spec.rb +0 -51
- data/spec/extensions/active_model_spec.rb +0 -85
- 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 -405
- data/spec/extensions/association_proxies_spec.rb +0 -86
- data/spec/extensions/auto_validations_spec.rb +0 -192
- data/spec/extensions/before_after_save_spec.rb +0 -40
- 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/boolean_subsets_spec.rb +0 -47
- data/spec/extensions/caching_spec.rb +0 -270
- data/spec/extensions/class_table_inheritance_spec.rb +0 -444
- 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_expiration_spec.rb +0 -121
- data/spec/extensions/connection_validator_spec.rb +0 -127
- data/spec/extensions/constraint_validations_plugin_spec.rb +0 -288
- data/spec/extensions/constraint_validations_spec.rb +0 -389
- data/spec/extensions/core_refinements_spec.rb +0 -519
- data/spec/extensions/csv_serializer_spec.rb +0 -180
- data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
- data/spec/extensions/dataset_associations_spec.rb +0 -343
- data/spec/extensions/dataset_source_alias_spec.rb +0 -51
- data/spec/extensions/date_arithmetic_spec.rb +0 -167
- data/spec/extensions/defaults_setter_spec.rb +0 -102
- data/spec/extensions/delay_add_association_spec.rb +0 -74
- data/spec/extensions/dirty_spec.rb +0 -180
- data/spec/extensions/duplicate_columns_handler_spec.rb +0 -110
- data/spec/extensions/eager_each_spec.rb +0 -66
- 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 -119
- data/spec/extensions/hash_aliases_spec.rb +0 -24
- data/spec/extensions/hook_class_methods_spec.rb +0 -429
- data/spec/extensions/identifier_columns_spec.rb +0 -17
- 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 -304
- data/spec/extensions/lazy_attributes_spec.rb +0 -170
- data/spec/extensions/list_spec.rb +0 -278
- 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 -728
- 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/no_auto_literal_strings_spec.rb +0 -65
- 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 -390
- 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 -275
- 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 -473
- 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 -814
- 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/server_logging_spec.rb +0 -45
- 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_comments_spec.rb +0 -27
- data/spec/extensions/sql_expr_spec.rb +0 -60
- data/spec/extensions/static_cache_spec.rb +0 -361
- data/spec/extensions/string_agg_spec.rb +0 -85
- 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/subset_conditions_spec.rb +0 -38
- data/spec/extensions/table_select_spec.rb +0 -71
- data/spec/extensions/tactical_eager_loading_spec.rb +0 -136
- 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/uuid_spec.rb +0 -106
- 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 -554
- 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/double_migration/001_create_sessions.rb +0 -9
- data/spec/files/double_migration/002_create_nodes.rb +0 -19
- data/spec/files/double_migration/003_3_create_users.rb +0 -4
- 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/empty_migration/001_create_sessions.rb +0 -9
- data/spec/files/empty_migration/002_create_nodes.rb +0 -0
- data/spec/files/empty_migration/003_3_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/reversible_migrations/006_reversible.rb +0 -10
- data/spec/files/reversible_migrations/007_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 -2506
- data/spec/integration/database_test.rb +0 -113
- data/spec/integration/dataset_test.rb +0 -1858
- data/spec/integration/eager_loader_test.rb +0 -687
- data/spec/integration/migrator_test.rb +0 -262
- data/spec/integration/model_test.rb +0 -230
- data/spec/integration/plugin_test.rb +0 -2297
- data/spec/integration/prepared_statement_test.rb +0 -467
- data/spec/integration/schema_test.rb +0 -815
- data/spec/integration/spec_helper.rb +0 -56
- data/spec/integration/timezone_test.rb +0 -86
- data/spec/integration/transaction_test.rb +0 -406
- data/spec/integration/type_test.rb +0 -133
- data/spec/model/association_reflection_spec.rb +0 -565
- data/spec/model/associations_spec.rb +0 -4589
- data/spec/model/base_spec.rb +0 -759
- data/spec/model/class_dataset_methods_spec.rb +0 -150
- data/spec/model/dataset_methods_spec.rb +0 -149
- data/spec/model/eager_loading_spec.rb +0 -2197
- data/spec/model/hooks_spec.rb +0 -604
- data/spec/model/inflector_spec.rb +0 -26
- data/spec/model/model_spec.rb +0 -1097
- data/spec/model/plugins_spec.rb +0 -299
- data/spec/model/record_spec.rb +0 -2162
- data/spec/model/spec_helper.rb +0 -46
- data/spec/model/validations_spec.rb +0 -193
- data/spec/model_no_assoc_spec.rb +0 -1
- data/spec/model_spec.rb +0 -1
- data/spec/plugin_spec.rb +0 -1
- data/spec/sequel_coverage.rb +0 -15
- data/spec/spec_config.rb +0 -10
data/lib/sequel/model/base.rb
CHANGED
@@ -7,16 +7,23 @@ module Sequel
|
|
7
7
|
|
8
8
|
# Class methods for Sequel::Model that implement basic model functionality.
|
9
9
|
#
|
10
|
-
# * All of the
|
11
|
-
# 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
|
12
24
|
module ClassMethods
|
13
|
-
#
|
14
|
-
#
|
15
|
-
attr_reader :allowed_columns
|
16
|
-
|
17
|
-
# Whether to cache the anonymous models created by Sequel::Model(). This is
|
18
|
-
# required for reloading them correctly (avoiding the superclass mismatch). True
|
19
|
-
# by default for backwards compatibility.
|
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).
|
20
27
|
attr_accessor :cache_anonymous_models
|
21
28
|
|
22
29
|
# Array of modules that extend this model's dataset. Stored
|
@@ -24,6 +31,9 @@ module Sequel
|
|
24
31
|
# with all of these modules.
|
25
32
|
attr_reader :dataset_method_modules
|
26
33
|
|
34
|
+
# The Module subclass to use for dataset_module blocks.
|
35
|
+
attr_reader :dataset_module_class
|
36
|
+
|
27
37
|
# The default options to use for Model#set_fields. These are merged with
|
28
38
|
# the options given to set_fields.
|
29
39
|
attr_accessor :default_set_fields_options
|
@@ -32,6 +42,10 @@ module Sequel
|
|
32
42
|
# model instances, or nil if the optimization should not be used. For internal use only.
|
33
43
|
attr_reader :fast_instance_delete_sql
|
34
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
|
+
|
35
49
|
# The dataset that instance datasets (#this) are based on. Generally a naked version of
|
36
50
|
# the model's dataset limited to one row. For internal use only.
|
37
51
|
attr_reader :instance_dataset
|
@@ -62,24 +76,10 @@ module Sequel
|
|
62
76
|
# Sequel will not check the number of rows modified (default: true).
|
63
77
|
attr_accessor :require_modification
|
64
78
|
|
65
|
-
#
|
66
|
-
# without a valid table backing it.
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# set_dataset :my_foo
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# As when Sequel::Model is subclassed, before set_dataset is executed, it will try to
|
73
|
-
# get the schema for the foos table, which will raise an exception. You would need to
|
74
|
-
# switch to using:
|
75
|
-
#
|
76
|
-
# class Foo < Sequel::Model(:my_foo)
|
77
|
-
# end
|
78
|
-
#
|
79
|
-
# or:
|
80
|
-
#
|
81
|
-
# Foo = Sequel::Model()
|
82
|
-
# Foo.set_dataset :my_foo
|
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
83
|
attr_accessor :require_valid_table
|
84
84
|
|
85
85
|
# Should be the literal primary key column name if this Model's table has a simple primary key, or
|
@@ -90,7 +90,7 @@ module Sequel
|
|
90
90
|
# or nil otherwise. This and simple_pk are used for an optimization in Model.[].
|
91
91
|
attr_reader :simple_table
|
92
92
|
|
93
|
-
# Whether new
|
93
|
+
# Whether mass assigning via .create/.new/#set/#update should raise an error
|
94
94
|
# if an invalid key is used. A key is invalid if no setter method exists
|
95
95
|
# for that key or the access to the setter method is restricted (e.g. due to it
|
96
96
|
# being a primary key field). If set to false, silently skip
|
@@ -109,11 +109,6 @@ module Sequel
|
|
109
109
|
# database to typecast the value correctly.
|
110
110
|
attr_accessor :typecast_on_assignment
|
111
111
|
|
112
|
-
# Whether to enable the after_commit and after_rollback hooks when saving/destroying
|
113
|
-
# instances. On by default, can be turned off for performance reasons or when using
|
114
|
-
# prepared transactions (which aren't compatible with after commit/rollback).
|
115
|
-
attr_accessor :use_after_commit_rollback
|
116
|
-
|
117
112
|
# Whether to use a transaction by default when saving/deleting records (default: true).
|
118
113
|
# If you are sending database queries in before_* or after_* hooks, you shouldn't change
|
119
114
|
# the default setting without a good reason.
|
@@ -141,7 +136,7 @@ module Sequel
|
|
141
136
|
# end
|
142
137
|
def def_Model(mod)
|
143
138
|
model = self
|
144
|
-
|
139
|
+
mod.define_singleton_method(:Model) do |source|
|
145
140
|
model.Model(source)
|
146
141
|
end
|
147
142
|
end
|
@@ -161,9 +156,8 @@ module Sequel
|
|
161
156
|
# classes in order to create the dataset.
|
162
157
|
#
|
163
158
|
# The purpose of this method is to set the dataset/database automatically
|
164
|
-
# for a model class, if the table name doesn't match the
|
165
|
-
# name
|
166
|
-
# doesn't require a bogus query for the schema.
|
159
|
+
# for a model class, if the table name doesn't match the default table
|
160
|
+
# name that Sequel would use.
|
167
161
|
#
|
168
162
|
# When creating subclasses of Sequel::Model itself, this method is usually
|
169
163
|
# called on Sequel itself, using <tt>Sequel::Model(:something)</tt>.
|
@@ -184,10 +178,8 @@ module Sequel
|
|
184
178
|
# end
|
185
179
|
def Model(source)
|
186
180
|
if cache_anonymous_models
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
if klass = mutex.synchronize{cache[source]}
|
181
|
+
cache = Sequel.synchronize{@Model_cache ||= {}}
|
182
|
+
if klass = Sequel.synchronize{cache[source]}
|
191
183
|
return klass
|
192
184
|
end
|
193
185
|
end
|
@@ -201,7 +193,7 @@ module Sequel
|
|
201
193
|
end
|
202
194
|
|
203
195
|
if cache_anonymous_models
|
204
|
-
|
196
|
+
Sequel.synchronize{cache[source] = klass}
|
205
197
|
end
|
206
198
|
|
207
199
|
klass
|
@@ -215,11 +207,11 @@ module Sequel
|
|
215
207
|
# Artist[1] # SELECT * FROM artists WHERE id = 1
|
216
208
|
# # => #<Artist {:id=>1, ...}>
|
217
209
|
#
|
218
|
-
# Artist[:
|
210
|
+
# Artist[name: 'Bob'] # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
219
211
|
# # => #<Artist {:name=>'Bob', ...}>
|
220
212
|
def [](*args)
|
221
213
|
args = args.first if args.size <= 1
|
222
|
-
args.is_a?(Hash) ?
|
214
|
+
args.is_a?(Hash) ? first(args) : (primary_key_lookup(args) unless args.nil?)
|
223
215
|
end
|
224
216
|
|
225
217
|
# Initializes a model instance as an existing record. This constructor is
|
@@ -234,7 +226,7 @@ module Sequel
|
|
234
226
|
|
235
227
|
# Clear the setter_methods cache
|
236
228
|
def clear_setter_methods_cache
|
237
|
-
@setter_methods = nil
|
229
|
+
@setter_methods = nil unless frozen?
|
238
230
|
end
|
239
231
|
|
240
232
|
# Returns the columns in the result set in their original order.
|
@@ -245,18 +237,20 @@ module Sequel
|
|
245
237
|
# Artist.columns
|
246
238
|
# # => [:id, :name]
|
247
239
|
def columns
|
248
|
-
@columns
|
240
|
+
return @columns if @columns
|
241
|
+
return nil if frozen?
|
242
|
+
set_columns(dataset.naked.columns)
|
249
243
|
end
|
250
244
|
|
251
245
|
# Creates instance using new with the given values and block, and saves it.
|
252
246
|
#
|
253
|
-
# Artist.create(:
|
247
|
+
# Artist.create(name: 'Bob')
|
254
248
|
# # INSERT INTO artists (name) VALUES ('Bob')
|
255
249
|
#
|
256
250
|
# Artist.create do |a|
|
257
251
|
# a.name = 'Jim'
|
258
252
|
# end # INSERT INTO artists (name) VALUES ('Jim')
|
259
|
-
def create(values =
|
253
|
+
def create(values = OPTS, &block)
|
260
254
|
new(values, &block).save
|
261
255
|
end
|
262
256
|
|
@@ -279,49 +273,70 @@ module Sequel
|
|
279
273
|
# a plugin with the methods defined in DatasetMethods.
|
280
274
|
# This is the recommended way to add methods to model datasets.
|
281
275
|
#
|
282
|
-
# 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
|
283
277
|
# the underlying dataset. Otherwise an anonymous module is created, and
|
284
278
|
# if a block is given, it is module_evaled, allowing you do define
|
285
279
|
# dataset methods directly using the standard ruby def syntax.
|
286
280
|
# Returns the module given or the anonymous module created.
|
287
281
|
#
|
288
282
|
# # Usage with existing module
|
289
|
-
#
|
283
|
+
# Album.dataset_module Sequel::ColumnsIntrospection
|
290
284
|
#
|
291
285
|
# # Usage with anonymous module
|
292
|
-
#
|
286
|
+
# Album.dataset_module do
|
293
287
|
# def foo
|
294
288
|
# :bar
|
295
289
|
# end
|
296
290
|
# end
|
297
|
-
#
|
291
|
+
# Album.dataset.foo
|
298
292
|
# # => :bar
|
299
|
-
#
|
293
|
+
# Album.foo
|
300
294
|
# # => :bar
|
301
295
|
#
|
302
296
|
# Any anonymous modules created are actually instances of Sequel::Model::DatasetModule
|
303
|
-
# (a Module subclass), which allows you to call the subset method on them
|
304
|
-
#
|
305
|
-
#
|
306
|
-
#
|
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
|
307
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.
|
308
323
|
#
|
309
324
|
# Any public methods in the dataset module will have class methods created that
|
310
325
|
# call the method on the dataset, assuming that the class method is not already
|
311
326
|
# defined.
|
312
|
-
def dataset_module(mod = nil)
|
327
|
+
def dataset_module(mod = nil, &block)
|
313
328
|
if mod
|
314
|
-
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
|
315
330
|
dataset_extend(mod)
|
316
331
|
mod
|
317
332
|
else
|
318
|
-
@dataset_module ||=
|
319
|
-
@dataset_module.module_eval(&
|
333
|
+
@dataset_module ||= dataset_module_class.new(self)
|
334
|
+
@dataset_module.module_eval(&block) if block
|
320
335
|
dataset_extend(@dataset_module)
|
321
336
|
@dataset_module
|
322
337
|
end
|
323
338
|
end
|
324
|
-
|
339
|
+
|
325
340
|
# Returns the database associated with the Model class.
|
326
341
|
# If this model doesn't have a database associated with it,
|
327
342
|
# assumes the superclass's database, or the first object in
|
@@ -329,7 +344,7 @@ module Sequel
|
|
329
344
|
# been created, raises an error.
|
330
345
|
#
|
331
346
|
# Artist.db.transaction do # BEGIN
|
332
|
-
# Artist.create(:
|
347
|
+
# Artist.create(name: 'Bob')
|
333
348
|
# # INSERT INTO artists (name) VALUES ('Bob')
|
334
349
|
# end # COMMIT
|
335
350
|
def db
|
@@ -339,23 +354,23 @@ module Sequel
|
|
339
354
|
@db
|
340
355
|
end
|
341
356
|
|
342
|
-
# Sets the database associated with the Model class.
|
343
|
-
#
|
344
|
-
#
|
345
|
-
#
|
346
|
-
# Sequel::Model to set the default database to be used
|
347
|
-
# by subclasses, or to override the database used for specific
|
348
|
-
# 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:
|
349
363
|
#
|
350
364
|
# Sequel::Model.db = DB1
|
365
|
+
# Artist = Class.new(Sequel::Model)
|
351
366
|
# Artist.db = DB2
|
352
367
|
#
|
353
368
|
# Note that you should not use this to change the model's database
|
354
369
|
# at runtime. If you have that need, you should look into Sequel's
|
355
|
-
# sharding support.
|
370
|
+
# sharding support, or consider using separate model classes per Database.
|
356
371
|
def db=(db)
|
372
|
+
raise Error, "Cannot use Sequel::Model.db= on model with existing dataset. Use Sequel::Model.dataset= instead." if @dataset
|
357
373
|
@db = db
|
358
|
-
set_dataset(db.dataset.clone(@dataset.opts)) if @dataset
|
359
374
|
end
|
360
375
|
|
361
376
|
# Returns the cached schema information if available or gets it
|
@@ -367,7 +382,9 @@ module Sequel
|
|
367
382
|
# # {:id=>{:type=>:integer, :primary_key=>true, ...},
|
368
383
|
# # :name=>{:type=>:string, :primary_key=>false, ...}}
|
369
384
|
def db_schema
|
370
|
-
@db_schema
|
385
|
+
return @db_schema if @db_schema
|
386
|
+
return nil if frozen?
|
387
|
+
@db_schema = get_db_schema
|
371
388
|
end
|
372
389
|
|
373
390
|
# Create a column alias, where the column methods have one name, but the underlying storage uses a
|
@@ -380,52 +397,16 @@ module Sequel
|
|
380
397
|
end
|
381
398
|
end
|
382
399
|
|
383
|
-
# If a block is given, define a method on the dataset (if the model currently has an dataset) with the given argument name using
|
384
|
-
# the given block. Also define a class method on the model that calls the
|
385
|
-
# dataset method. Stores the method name and block so that it can be reapplied if the model's
|
386
|
-
# dataset changes.
|
387
|
-
#
|
388
|
-
# If a block is not given, just define a class method on the model for each argument
|
389
|
-
# that calls the dataset method of the same argument name.
|
390
|
-
#
|
391
|
-
# It is recommended that you define methods inside a block passed to #dataset_module
|
392
|
-
# instead of using this method, as #dataset_module allows you to use normal
|
393
|
-
# ruby def syntax.
|
394
|
-
#
|
395
|
-
# # Add new dataset method and class method that calls it
|
396
|
-
# Artist.def_dataset_method(:by_name){order(:name)}
|
397
|
-
# Artist.filter(:name.like('A%')).by_name
|
398
|
-
# Artist.by_name.filter(:name.like('A%'))
|
399
|
-
#
|
400
|
-
# # Just add a class method that calls an existing dataset method
|
401
|
-
# Artist.def_dataset_method(:server!)
|
402
|
-
# Artist.server!(:server1)
|
403
|
-
def def_dataset_method(*args, &block)
|
404
|
-
raise(Error, "No arguments given") if args.empty?
|
405
|
-
|
406
|
-
if block
|
407
|
-
raise(Error, "Defining a dataset method using a block requires only one argument") if args.length > 1
|
408
|
-
dataset_module{define_method(args.first, &block)}
|
409
|
-
else
|
410
|
-
args.each{|arg| def_model_dataset_method(arg)}
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
400
|
# Finds a single record according to the supplied filter.
|
415
401
|
# You are encouraged to use Model.[] or Model.first instead of this method.
|
416
402
|
#
|
417
|
-
# Artist.find(:
|
403
|
+
# Artist.find(name: 'Bob')
|
418
404
|
# # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
419
405
|
#
|
420
406
|
# Artist.find{name > 'M'}
|
421
407
|
# # SELECT * FROM artists WHERE (name > 'M') LIMIT 1
|
422
408
|
def find(*args, &block)
|
423
|
-
|
424
|
-
# Use optimized finder
|
425
|
-
first_where(args.first)
|
426
|
-
else
|
427
|
-
filter(*args, &block).first
|
428
|
-
end
|
409
|
+
first(*args, &block)
|
429
410
|
end
|
430
411
|
|
431
412
|
# Like +find+ but invokes create with given conditions when record does not
|
@@ -433,154 +414,43 @@ module Sequel
|
|
433
414
|
# to +find+, but instead is passed to +create+ only if +find+ does not
|
434
415
|
# return an object.
|
435
416
|
#
|
436
|
-
# Artist.find_or_create(:
|
417
|
+
# Artist.find_or_create(name: 'Bob')
|
437
418
|
# # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
438
419
|
# # INSERT INTO artists (name) VALUES ('Bob')
|
439
420
|
#
|
440
|
-
# Artist.find_or_create(:
|
421
|
+
# Artist.find_or_create(name: 'Jim'){|a| a.hometown = 'Sactown'}
|
441
422
|
# # SELECT * FROM artists WHERE (name = 'Jim') LIMIT 1
|
442
423
|
# # INSERT INTO artists (name, hometown) VALUES ('Jim', 'Sactown')
|
443
424
|
def find_or_create(cond, &block)
|
444
425
|
find(cond) || create(cond, &block)
|
445
426
|
end
|
446
|
-
|
447
|
-
|
448
|
-
FINDER_TYPES = [:first, :all, :each, :get].freeze
|
449
|
-
|
450
|
-
# Create an optimized finder method using a dataset placeholder literalizer.
|
451
|
-
# This pre-computes the SQL to use for the query, except for given arguments.
|
452
|
-
#
|
453
|
-
# There are two ways to use this. The recommended way is to pass a symbol
|
454
|
-
# that represents a model class method that returns a dataset:
|
455
|
-
#
|
456
|
-
# def Artist.by_name(name)
|
457
|
-
# where(:name=>name)
|
458
|
-
# end
|
459
|
-
#
|
460
|
-
# Artist.finder :by_name
|
461
|
-
#
|
462
|
-
# This creates an optimized first_by_name method, which you can call normally:
|
463
|
-
#
|
464
|
-
# Artist.first_by_name("Joe")
|
465
|
-
#
|
466
|
-
# The alternative way to use this to pass your own block:
|
467
|
-
#
|
468
|
-
# Artist.finder(:name=>:first_by_name){|pl, ds| ds.where(:name=>pl.arg).limit(1)}
|
469
|
-
#
|
470
|
-
# Note that if you pass your own block, you are responsible for manually setting
|
471
|
-
# limits if necessary (as shown above).
|
472
|
-
#
|
473
|
-
# Options:
|
474
|
-
# :arity :: When using a symbol method name, this specifies the arity of the method.
|
475
|
-
# This should be used if if the method accepts an arbitrary number of arguments,
|
476
|
-
# or the method has default argument values. Note that if the method is defined
|
477
|
-
# as a dataset method, the class method Sequel creates accepts an arbitrary number
|
478
|
-
# of arguments, so you should use this option in that case. If you want to handle
|
479
|
-
# multiple possible arities, you need to call the finder method multiple times with
|
480
|
-
# unique :arity and :name methods each time.
|
481
|
-
# :name :: The name of the method to create. This must be given if you pass a block.
|
482
|
-
# If you use a symbol, this defaults to the symbol prefixed by the type.
|
483
|
-
# :mod :: The module in which to create the finder method. Defaults to the singleton
|
484
|
-
# class of the model.
|
485
|
-
# :type :: The type of query to run. Can be :first, :each, :all, or :get, defaults to
|
486
|
-
# :first.
|
487
|
-
#
|
488
|
-
# Caveats:
|
489
|
-
#
|
490
|
-
# This doesn't handle all possible cases. For example, if you have a method such as:
|
491
|
-
#
|
492
|
-
# def Artist.by_name(name)
|
493
|
-
# name ? where(:name=>name) : exclude(:name=>nil)
|
494
|
-
# end
|
495
|
-
#
|
496
|
-
# Then calling a finder without an argument will not work as you expect.
|
497
|
-
#
|
498
|
-
# Artist.finder :by_name
|
499
|
-
# Artist.by_name(nil).first
|
500
|
-
# # WHERE (name IS NOT NULL)
|
501
|
-
# Artist.first_by_name(nil)
|
502
|
-
# # WHERE (name IS NULL)
|
503
|
-
#
|
504
|
-
# See Dataset::PlaceholderLiteralizer for additional caveats.
|
505
|
-
def finder(meth=OPTS, opts=OPTS, &block)
|
506
|
-
if block
|
507
|
-
raise Error, "cannot pass both a method name argument and a block of Model.finder" unless meth.is_a?(Hash)
|
508
|
-
raise Error, "cannot pass two option hashes to Model.finder" unless opts.equal?(OPTS)
|
509
|
-
opts = meth
|
510
|
-
raise Error, "must provide method name via :name option when passing block to Model.finder" unless meth_name = opts[:name]
|
511
|
-
end
|
512
|
-
|
513
|
-
type = opts.fetch(:type, :first)
|
514
|
-
unless prepare = opts[:prepare]
|
515
|
-
raise Error, ":type option to Model.finder must be :first, :all, :each, or :get" unless FINDER_TYPES.include?(type)
|
516
|
-
end
|
517
|
-
limit1 = type == :first || type == :get
|
518
|
-
meth_name ||= opts[:name] || :"#{type}_#{meth}"
|
519
|
-
|
520
|
-
argn = lambda do |model|
|
521
|
-
if arity = opts[:arity]
|
522
|
-
arity
|
523
|
-
else
|
524
|
-
method = block || model.method(meth)
|
525
|
-
(method.arity < 0 ? method.arity.abs - 1 : method.arity)
|
526
|
-
end
|
527
|
-
end
|
528
427
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
if model_name.to_s.empty?
|
540
|
-
model_name = model.object_id
|
541
|
-
else
|
542
|
-
model_name = model_name.gsub(/\W/, '_')
|
543
|
-
end
|
544
|
-
ds.prepare(type, :"#{model_name}_#{meth_name}")
|
545
|
-
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
|
546
438
|
else
|
547
|
-
|
548
|
-
n = argn.call(model)
|
549
|
-
block ||= lambda do |pl, model2|
|
550
|
-
args = (0...n).map{pl.arg}
|
551
|
-
ds = model2.send(meth, *args)
|
552
|
-
ds = ds.limit(1) if limit1
|
553
|
-
ds
|
554
|
-
end
|
555
|
-
|
556
|
-
Sequel::Dataset::PlaceholderLiteralizer.loader(model, &block)
|
557
|
-
end
|
439
|
+
@setter_methods = [].freeze
|
558
440
|
end
|
559
441
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
def_prepare_method(mod, meth_name)
|
564
|
-
else
|
565
|
-
def_finder_method(mod, meth_name, type)
|
566
|
-
end
|
567
|
-
end
|
442
|
+
@dataset_method_modules.freeze
|
443
|
+
@default_set_fields_options.freeze
|
444
|
+
@plugins.freeze
|
568
445
|
|
569
|
-
|
570
|
-
# optimized handling of the single argument case.
|
571
|
-
def first(*args, &block)
|
572
|
-
if args.length == 1 && !block && !args.first.is_a?(Integer)
|
573
|
-
# Use optimized finder
|
574
|
-
first_where(args.first)
|
575
|
-
else
|
576
|
-
dataset.first(*args, &block)
|
577
|
-
end
|
446
|
+
super
|
578
447
|
end
|
579
448
|
|
580
|
-
#
|
581
|
-
#
|
582
|
-
|
583
|
-
|
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?
|
584
454
|
end
|
585
455
|
|
586
456
|
# Clear the setter_methods cache when a module is included, as it
|
@@ -590,47 +460,6 @@ module Sequel
|
|
590
460
|
super
|
591
461
|
end
|
592
462
|
|
593
|
-
# If possible, set the dataset for the model subclass as soon as it
|
594
|
-
# is created. Also, make sure the inherited class instance variables
|
595
|
-
# are copied into the subclass.
|
596
|
-
#
|
597
|
-
# Sequel queries the database to get schema information as soon as
|
598
|
-
# a model class is created:
|
599
|
-
#
|
600
|
-
# class Artist < Sequel::Model # Causes schema query
|
601
|
-
# end
|
602
|
-
def inherited(subclass)
|
603
|
-
super
|
604
|
-
ivs = subclass.instance_variables.collect(&:to_s)
|
605
|
-
inherited_instance_variables.each do |iv, dup|
|
606
|
-
next if ivs.include?(iv.to_s)
|
607
|
-
if (sup_class_value = instance_variable_get(iv)) && dup
|
608
|
-
sup_class_value = case dup
|
609
|
-
when :dup
|
610
|
-
sup_class_value.dup
|
611
|
-
when :hash_dup
|
612
|
-
h = {}
|
613
|
-
sup_class_value.each{|k,v| h[k] = v.dup}
|
614
|
-
h
|
615
|
-
when Proc
|
616
|
-
dup.call(sup_class_value)
|
617
|
-
else
|
618
|
-
raise Error, "bad inherited instance variable type: #{dup.inspect}"
|
619
|
-
end
|
620
|
-
end
|
621
|
-
subclass.instance_variable_set(iv, sup_class_value)
|
622
|
-
end
|
623
|
-
|
624
|
-
unless ivs.include?("@dataset")
|
625
|
-
if @dataset && self != Model
|
626
|
-
subclass.set_dataset(@dataset.clone, :inherited=>true)
|
627
|
-
elsif (n = subclass.name) && !n.to_s.empty?
|
628
|
-
db
|
629
|
-
subclass.set_dataset(subclass.implicit_table_name)
|
630
|
-
end
|
631
|
-
end
|
632
|
-
end
|
633
|
-
|
634
463
|
# Returns the implicit table name for the model class, which is the demodulized,
|
635
464
|
# underscored, pluralized name of the class.
|
636
465
|
#
|
@@ -640,17 +469,11 @@ module Sequel
|
|
640
469
|
pluralize(underscore(demodulize(name))).to_sym
|
641
470
|
end
|
642
471
|
|
643
|
-
# Calls #call with the values hash.
|
472
|
+
# Calls #call with the values hash.
|
644
473
|
def load(values)
|
645
474
|
call(values)
|
646
475
|
end
|
647
476
|
|
648
|
-
# Clear the setter_methods cache when a setter method is added
|
649
|
-
def method_added(meth)
|
650
|
-
clear_setter_methods_cache if meth.to_s =~ SETTER_METHOD_REGEXP
|
651
|
-
super
|
652
|
-
end
|
653
|
-
|
654
477
|
# Mark the model as not having a primary key. Not having a primary key
|
655
478
|
# can cause issues, among which is that you won't be able to update records.
|
656
479
|
#
|
@@ -664,22 +487,30 @@ module Sequel
|
|
664
487
|
|
665
488
|
# Loads a plugin for use with the model class, passing optional arguments
|
666
489
|
# to the plugin. If the plugin is a module, load it directly. Otherwise,
|
667
|
-
# require the plugin from
|
668
|
-
#
|
669
|
-
# 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.
|
670
492
|
def plugin(plugin, *args, &block)
|
671
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
|
+
|
672
499
|
unless @plugins.include?(m)
|
673
500
|
@plugins << m
|
674
501
|
m.apply(self, *args, &block) if m.respond_to?(:apply)
|
675
|
-
extend(m::ClassMethods) if
|
676
|
-
include(m::InstanceMethods) if
|
677
|
-
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)
|
678
505
|
dataset_extend(m::DatasetMethods, :create_class_methods=>false)
|
679
506
|
end
|
680
507
|
end
|
508
|
+
|
681
509
|
m.configure(self, *args, &block) if m.respond_to?(:configure)
|
682
510
|
end
|
511
|
+
# :nocov:
|
512
|
+
ruby2_keywords(:plugin) if respond_to?(:ruby2_keywords, true)
|
513
|
+
# :nocov:
|
683
514
|
|
684
515
|
# Returns primary key attribute hash. If using a composite primary key
|
685
516
|
# value such be an array with values for each primary key in the correct
|
@@ -707,7 +538,7 @@ module Sequel
|
|
707
538
|
# plan to join other tables to this table and you want the column references
|
708
539
|
# to be qualified.
|
709
540
|
#
|
710
|
-
# Artist.
|
541
|
+
# Artist.where(Artist.qualified_primary_key_hash(1))
|
711
542
|
# # SELECT * FROM artists WHERE (artists.id = 1)
|
712
543
|
def qualified_primary_key_hash(value, qualifier=table_name)
|
713
544
|
case key = @primary_key
|
@@ -722,27 +553,6 @@ module Sequel
|
|
722
553
|
end
|
723
554
|
end
|
724
555
|
|
725
|
-
# Similar to finder, but uses a prepared statement instead of a placeholder
|
726
|
-
# literalizer. This makes the SQL used static (cannot vary per call), but
|
727
|
-
# allows binding argument values instead of literalizing them into the SQL
|
728
|
-
# query string.
|
729
|
-
#
|
730
|
-
# If a block is used with this method, it is instance_execed by the model,
|
731
|
-
# and should accept the desired number of placeholder arguments.
|
732
|
-
#
|
733
|
-
# The options are the same as the options for finder, with the following
|
734
|
-
# exception:
|
735
|
-
# :type :: Specifies the type of prepared statement to create
|
736
|
-
def prepared_finder(meth=OPTS, opts=OPTS, &block)
|
737
|
-
if block
|
738
|
-
raise Error, "cannot pass both a method name argument and a block of Model.finder" unless meth.is_a?(Hash)
|
739
|
-
meth = meth.merge(:prepare=>true)
|
740
|
-
else
|
741
|
-
opts = opts.merge(:prepare=>true)
|
742
|
-
end
|
743
|
-
finder(meth, opts, &block)
|
744
|
-
end
|
745
|
-
|
746
556
|
# Restrict the setting of the primary key(s) when using mass assignment (e.g. +set+). Because
|
747
557
|
# this is the default, this only make sense to use in a subclass where the
|
748
558
|
# parent class has used +unrestrict_primary_key+.
|
@@ -757,22 +567,6 @@ module Sequel
|
|
757
567
|
@restrict_primary_key
|
758
568
|
end
|
759
569
|
|
760
|
-
# Set the columns to allow when using mass assignment (e.g. +set+). Using this means that
|
761
|
-
# any columns not listed here will not be modified. If you have any virtual
|
762
|
-
# setter methods (methods that end in =) that you want to be used during
|
763
|
-
# mass assignment, they need to be listed here as well (without the =).
|
764
|
-
#
|
765
|
-
# It may be better to use a method such as +set_only+ or +set_fields+ that lets you specify
|
766
|
-
# the allowed fields per call.
|
767
|
-
#
|
768
|
-
# Artist.set_allowed_columns(:name, :hometown)
|
769
|
-
# Artist.set(:name=>'Bob', :hometown=>'Sactown') # No Error
|
770
|
-
# Artist.set(:name=>'Bob', :records_sold=>30000) # Error
|
771
|
-
def set_allowed_columns(*cols)
|
772
|
-
clear_setter_methods_cache
|
773
|
-
@allowed_columns = cols
|
774
|
-
end
|
775
|
-
|
776
570
|
# Sets the dataset associated with the Model class. +ds+ can be a +Symbol+,
|
777
571
|
# +LiteralString+, <tt>SQL::Identifier</tt>, <tt>SQL::QualifiedIdentifier</tt>,
|
778
572
|
# <tt>SQL::AliasedExpression</tt>
|
@@ -782,38 +576,43 @@ module Sequel
|
|
782
576
|
# database with the table name given. Other arguments raise an +Error+.
|
783
577
|
# Returns self.
|
784
578
|
#
|
785
|
-
# This changes the row_proc of the dataset to return
|
786
|
-
# model objects and extends the dataset with the dataset_method_modules.
|
787
579
|
# It also attempts to determine the database schema for the model,
|
788
580
|
# based on the given dataset.
|
789
581
|
#
|
790
|
-
# Artist.set_dataset(:tbl_artists)
|
791
|
-
# Artist.set_dataset(DB[:artists])
|
792
|
-
#
|
793
582
|
# Note that you should not use this to change the model's dataset
|
794
583
|
# at runtime. If you have that need, you should look into Sequel's
|
795
|
-
# sharding support
|
584
|
+
# sharding support, or creating a separate Model class per dataset
|
585
|
+
#
|
586
|
+
# You should avoid calling this method directly if possible. Instead you should
|
587
|
+
# set the table name or dataset when creating the model class:
|
588
|
+
#
|
589
|
+
# # table name
|
590
|
+
# class Artist < Sequel::Model(:tbl_artists)
|
591
|
+
# end
|
592
|
+
#
|
593
|
+
# # dataset
|
594
|
+
# class Artist < Sequel::Model(DB[:tbl_artists])
|
595
|
+
# end
|
796
596
|
def set_dataset(ds, opts=OPTS)
|
797
597
|
inherited = opts[:inherited]
|
798
598
|
@dataset = convert_input_dataset(ds)
|
799
|
-
@require_modification =
|
599
|
+
@require_modification = @dataset.provides_accurate_rows_matched? if require_modification.nil?
|
800
600
|
if inherited
|
801
601
|
self.simple_table = superclass.simple_table
|
802
602
|
@columns = superclass.instance_variable_get(:@columns)
|
803
603
|
@db_schema = superclass.instance_variable_get(:@db_schema)
|
804
604
|
else
|
805
|
-
@
|
605
|
+
@dataset = @dataset.with_extend(*@dataset_method_modules.reverse)
|
806
606
|
@db_schema = get_db_schema
|
807
607
|
end
|
808
608
|
|
809
|
-
@dataset.model = self if @dataset.respond_to?(:model=)
|
810
609
|
reset_instance_dataset
|
811
610
|
self
|
812
611
|
end
|
813
612
|
|
814
613
|
# Sets the primary key for this model. You can use either a regular
|
815
614
|
# or a composite primary key. To not use a primary key, set to nil
|
816
|
-
# or use +no_primary_key+.
|
615
|
+
# or use +no_primary_key+. On most adapters, Sequel can automatically
|
817
616
|
# determine the primary key to use, so this method is not needed often.
|
818
617
|
#
|
819
618
|
# class Person < Sequel::Model
|
@@ -835,48 +634,22 @@ module Sequel
|
|
835
634
|
end
|
836
635
|
end
|
837
636
|
self.simple_pk = if key && !key.is_a?(Array)
|
838
|
-
(@dataset || db).literal(key)
|
637
|
+
(@dataset || db).literal(key).freeze
|
839
638
|
end
|
840
639
|
@primary_key = key
|
841
640
|
end
|
842
641
|
|
843
|
-
# Cache of setter methods to allow by default, in order to speed up
|
642
|
+
# Cache of setter methods to allow by default, in order to speed up mass assignment.
|
844
643
|
def setter_methods
|
845
|
-
@setter_methods
|
644
|
+
@setter_methods || (@setter_methods = get_setter_methods)
|
846
645
|
end
|
847
646
|
|
848
|
-
# Sets up a dataset method that returns a filtered dataset.
|
849
|
-
# Sometimes thought of as a scope, and like most dataset methods,
|
850
|
-
# they can be chained.
|
851
|
-
# For example:
|
852
|
-
#
|
853
|
-
# Topic.subset(:joes, :username.like('%joe%'))
|
854
|
-
# Topic.subset(:popular){num_posts > 100}
|
855
|
-
# Topic.subset(:recent){created_on > Date.today - 7}
|
856
|
-
#
|
857
|
-
# Allows you to do:
|
858
|
-
#
|
859
|
-
# Topic.joes.recent.popular
|
860
|
-
#
|
861
|
-
# to get topics with a username that includes joe that
|
862
|
-
# have more than 100 posts and were created less than
|
863
|
-
# 7 days ago.
|
864
|
-
#
|
865
|
-
# Both the args given and the block are passed to <tt>Dataset#filter</tt>.
|
866
|
-
#
|
867
|
-
# This method creates dataset methods that do not accept arguments. To create
|
868
|
-
# dataset methods that accept arguments, you should use define a
|
869
|
-
# method directly inside a #dataset_module block.
|
870
|
-
def subset(name, *args, &block)
|
871
|
-
def_dataset_method(name){filter(*args, &block)}
|
872
|
-
end
|
873
|
-
|
874
647
|
# Returns name of primary table for the dataset. If the table for the dataset
|
875
648
|
# is aliased, returns the aliased name.
|
876
649
|
#
|
877
650
|
# Artist.table_name # => :artists
|
878
651
|
# Sequel::Model(:foo).table_name # => :foo
|
879
|
-
# Sequel::Model(:
|
652
|
+
# Sequel::Model(Sequel[:foo].as(:bar)).table_name # => :bar
|
880
653
|
def table_name
|
881
654
|
dataset.first_source_alias
|
882
655
|
end
|
@@ -884,9 +657,9 @@ module Sequel
|
|
884
657
|
# Allow the setting of the primary key(s) when using the mass assignment methods.
|
885
658
|
# Using this method can open up security issues, be very careful before using it.
|
886
659
|
#
|
887
|
-
# Artist.set(:
|
660
|
+
# Artist.set(id: 1) # Error
|
888
661
|
# Artist.unrestrict_primary_key
|
889
|
-
# Artist.set(:
|
662
|
+
# Artist.set(id: 1) # No Error
|
890
663
|
def unrestrict_primary_key
|
891
664
|
clear_setter_methods_cache
|
892
665
|
@restrict_primary_key = false
|
@@ -903,45 +676,49 @@ module Sequel
|
|
903
676
|
end
|
904
677
|
|
905
678
|
# Add model methods that call dataset methods
|
906
|
-
Plugins.def_dataset_methods(self,
|
679
|
+
Plugins.def_dataset_methods(self, (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS + [:each_server]) - [:<<, :or, :[], :columns, :columns!, :delete, :update, :set_graph_aliases, :add_graph_aliases])
|
907
680
|
|
908
681
|
private
|
909
682
|
|
910
|
-
# Yield to the passed block and swallow
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
end
|
683
|
+
# Yield to the passed block and if do_raise is false, swallow Sequel::Errors other than DatabaseConnectionError
|
684
|
+
# and DatabaseDisconnectError.
|
685
|
+
def check_non_connection_error(do_raise=require_valid_table)
|
686
|
+
db.transaction(:savepoint=>:only){yield}
|
687
|
+
rescue Sequel::DatabaseConnectionError, Sequel::DatabaseDisconnectError
|
688
|
+
raise
|
689
|
+
rescue Sequel::Error
|
690
|
+
raise if do_raise
|
919
691
|
end
|
920
692
|
|
921
693
|
# Convert the given object to a Dataset that should be used as
|
922
694
|
# this model's dataset.
|
923
695
|
def convert_input_dataset(ds)
|
924
696
|
case ds
|
925
|
-
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier
|
926
|
-
self.simple_table = db.literal(ds)
|
697
|
+
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier
|
698
|
+
self.simple_table = db.literal(ds).freeze
|
699
|
+
ds = db.from(ds)
|
700
|
+
when SQL::AliasedExpression, LiteralString
|
701
|
+
self.simple_table = nil
|
927
702
|
ds = db.from(ds)
|
928
703
|
when Dataset
|
704
|
+
ds = ds.from_self(:alias=>ds.first_source) if ds.joined_dataset?
|
705
|
+
|
929
706
|
self.simple_table = if ds.send(:simple_select_all?)
|
930
|
-
ds.literal(ds.first_source_table)
|
707
|
+
ds.literal(ds.first_source_table).freeze
|
931
708
|
end
|
932
709
|
@db = ds.db
|
933
710
|
else
|
934
711
|
raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
|
935
712
|
end
|
936
|
-
|
937
|
-
ds
|
713
|
+
|
714
|
+
set_dataset_row_proc(ds.clone(:model=>self))
|
938
715
|
end
|
939
716
|
|
940
717
|
# Add the module to the class's dataset_method_modules. Extend the dataset with the
|
941
718
|
# module if the model has a dataset. Add dataset methods to the class for all
|
942
719
|
# public dataset methods.
|
943
720
|
def dataset_extend(mod, opts=OPTS)
|
944
|
-
@dataset.
|
721
|
+
@dataset = @dataset.with_extend(mod) if @dataset
|
945
722
|
reset_instance_dataset
|
946
723
|
dataset_method_modules << mod
|
947
724
|
unless opts[:create_class_methods] == false
|
@@ -951,9 +728,17 @@ module Sequel
|
|
951
728
|
|
952
729
|
# Create a column accessor for a column with a method name that is hard to use in ruby code.
|
953
730
|
def def_bad_column_accessor(column)
|
731
|
+
im = instance_methods
|
954
732
|
overridable_methods_module.module_eval do
|
955
|
-
|
956
|
-
|
733
|
+
meth = :"#{column}="
|
734
|
+
unless im.include?(column)
|
735
|
+
define_method(column){self[column]}
|
736
|
+
alias_method(column, column)
|
737
|
+
end
|
738
|
+
unless im.include?(meth)
|
739
|
+
define_method(meth){|v| self[column] = v}
|
740
|
+
alias_method(meth, meth)
|
741
|
+
end
|
957
742
|
end
|
958
743
|
end
|
959
744
|
|
@@ -961,51 +746,37 @@ module Sequel
|
|
961
746
|
# use a string to define the method for speed. For other columns names, use a block.
|
962
747
|
def def_column_accessor(*columns)
|
963
748
|
clear_setter_methods_cache
|
964
|
-
columns, bad_columns = columns.partition{|x|
|
749
|
+
columns, bad_columns = columns.partition{|x| /\A[A-Za-z_][A-Za-z0-9_]*\z/.match(x.to_s)}
|
965
750
|
bad_columns.each{|x| def_bad_column_accessor(x)}
|
966
|
-
im = instance_methods
|
751
|
+
im = instance_methods
|
967
752
|
columns.each do |column|
|
968
|
-
meth = "#{column}="
|
969
|
-
|
970
|
-
|
753
|
+
meth = :"#{column}="
|
754
|
+
unless im.include?(column)
|
755
|
+
overridable_methods_module.module_eval("def #{column}; self[:#{column}] end", __FILE__, __LINE__)
|
756
|
+
overridable_methods_module.send(:alias_method, column, column)
|
757
|
+
end
|
758
|
+
unless im.include?(meth)
|
759
|
+
overridable_methods_module.module_eval("def #{meth}(v); self[:#{column}] = v end", __FILE__, __LINE__)
|
760
|
+
overridable_methods_module.send(:alias_method, meth, meth)
|
761
|
+
end
|
971
762
|
end
|
972
763
|
end
|
973
764
|
|
974
765
|
# Define a model method that calls the dataset method with the same name,
|
975
|
-
# only used for methods with names that can't be
|
766
|
+
# only used for methods with names that can't be represented directly in
|
976
767
|
# ruby code.
|
977
768
|
def def_model_dataset_method(meth)
|
978
769
|
return if respond_to?(meth, true)
|
979
770
|
|
980
|
-
if meth.to_s =~
|
771
|
+
if meth.to_s =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
981
772
|
instance_eval("def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end", __FILE__, __LINE__)
|
982
773
|
else
|
983
|
-
(
|
984
|
-
end
|
985
|
-
end
|
986
|
-
|
987
|
-
# Define a finder method in the given module with the given method name that
|
988
|
-
# load rows using the finder with the given name.
|
989
|
-
def def_finder_method(mod, meth, type)
|
990
|
-
mod.send(:define_method, meth){|*args, &block| finder_for(meth).send(type, *args, &block)}
|
991
|
-
end
|
992
|
-
|
993
|
-
# Define a prepared_finder method in the given module that will call the associated prepared
|
994
|
-
# statement.
|
995
|
-
def def_prepare_method(mod, meth)
|
996
|
-
mod.send(:define_method, meth){|*args, &block| finder_for(meth).call(prepare_method_arg_hash(args), &block)}
|
997
|
-
end
|
998
|
-
|
999
|
-
# Find the finder to use for the give method. If a finder has not been loaded
|
1000
|
-
# for the method, load the finder and set correctly in the finders hash, then
|
1001
|
-
# return the finder.
|
1002
|
-
def finder_for(meth)
|
1003
|
-
unless finder = Sequel.synchronize{@finders[meth]}
|
1004
|
-
finder_loader = @finder_loaders.fetch(meth)
|
1005
|
-
finder = finder_loader.call(self)
|
1006
|
-
Sequel.synchronize{@finders[meth] = finder}
|
774
|
+
define_singleton_method(meth){|*args, &block| dataset.public_send(meth, *args, &block)}
|
1007
775
|
end
|
1008
|
-
|
776
|
+
singleton_class.send(:alias_method, meth, meth)
|
777
|
+
# :nocov:
|
778
|
+
singleton_class.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
779
|
+
# :nocov:
|
1009
780
|
end
|
1010
781
|
|
1011
782
|
# Get the schema from the database, fall back on checking the columns
|
@@ -1017,14 +788,14 @@ module Sequel
|
|
1017
788
|
schema_hash = {}
|
1018
789
|
ds_opts = dataset.opts
|
1019
790
|
get_columns = proc{check_non_connection_error{columns} || []}
|
1020
|
-
schema_array =
|
791
|
+
schema_array = get_db_schema_array(reload) if db.supports_schema_parsing?
|
1021
792
|
if schema_array
|
1022
793
|
schema_array.each{|k,v| schema_hash[k] = v}
|
1023
794
|
|
1024
795
|
# Set the primary key(s) based on the schema information,
|
1025
796
|
# if the schema information includes primary key information
|
1026
797
|
if schema_array.all?{|k,v| v.has_key?(:primary_key)}
|
1027
|
-
pks = schema_array.
|
798
|
+
pks = schema_array.map{|k,v| k if v[:primary_key]}.compact
|
1028
799
|
pks.length > 0 ? set_primary_key(pks) : no_primary_key
|
1029
800
|
end
|
1030
801
|
|
@@ -1039,11 +810,11 @@ module Sequel
|
|
1039
810
|
# Dataset is for a single table with all columns,
|
1040
811
|
# so set the columns based on the order they were
|
1041
812
|
# returned by the schema.
|
1042
|
-
cols = schema_array.
|
813
|
+
cols = schema_array.map{|k,v| k}
|
1043
814
|
set_columns(cols)
|
1044
815
|
# Also set the columns for the dataset, so the dataset
|
1045
816
|
# doesn't have to do a query to get them.
|
1046
|
-
dataset.
|
817
|
+
dataset.send(:columns=, cols)
|
1047
818
|
end
|
1048
819
|
else
|
1049
820
|
# If the dataset uses multiple tables or custom sql or getting
|
@@ -1054,24 +825,90 @@ module Sequel
|
|
1054
825
|
schema_hash
|
1055
826
|
end
|
1056
827
|
|
828
|
+
# Get the array of schema information for the dataset. Returns nil if
|
829
|
+
# the schema information cannot be determined.
|
830
|
+
def get_db_schema_array(reload)
|
831
|
+
check_non_connection_error(false){db.schema(dataset, :reload=>reload)}
|
832
|
+
end
|
833
|
+
|
1057
834
|
# Uncached version of setter_methods, to be overridden by plugins
|
1058
835
|
# that want to modify the methods used.
|
1059
836
|
def get_setter_methods
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
meths = instance_methods.collect(&:to_s).grep(SETTER_METHOD_REGEXP) - RESTRICTED_SETTER_METHODS
|
1064
|
-
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && restrict_primary_key?
|
1065
|
-
meths
|
1066
|
-
end
|
837
|
+
meths = instance_methods.map(&:to_s).select{|l| l.end_with?('=')} - RESTRICTED_SETTER_METHODS
|
838
|
+
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && restrict_primary_key?
|
839
|
+
meths
|
1067
840
|
end
|
1068
841
|
|
842
|
+
# If possible, set the dataset for the model subclass as soon as it
|
843
|
+
# is created. Also, make sure the inherited class instance variables
|
844
|
+
# are copied into the subclass.
|
845
|
+
#
|
846
|
+
# Sequel queries the database to get schema information as soon as
|
847
|
+
# a model class is created:
|
848
|
+
#
|
849
|
+
# class Artist < Sequel::Model # Causes schema query
|
850
|
+
# end
|
851
|
+
def inherited(subclass)
|
852
|
+
super
|
853
|
+
ivs = subclass.instance_variables
|
854
|
+
inherited_instance_variables.each do |iv, dup|
|
855
|
+
if (sup_class_value = instance_variable_get(iv)) && dup
|
856
|
+
sup_class_value = case dup
|
857
|
+
when :dup
|
858
|
+
sup_class_value.dup
|
859
|
+
when :hash_dup
|
860
|
+
h = {}
|
861
|
+
sup_class_value.each{|k,v| h[k] = v.dup}
|
862
|
+
h
|
863
|
+
when Proc
|
864
|
+
dup.call(sup_class_value)
|
865
|
+
else
|
866
|
+
raise Error, "bad inherited instance variable type: #{dup.inspect}"
|
867
|
+
end
|
868
|
+
end
|
869
|
+
subclass.instance_variable_set(iv, sup_class_value)
|
870
|
+
end
|
871
|
+
|
872
|
+
unless ivs.include?(:@dataset)
|
873
|
+
if @dataset && self != Model
|
874
|
+
subclass.set_dataset(@dataset.clone, :inherited=>true)
|
875
|
+
elsif (n = subclass.name) && !n.to_s.empty?
|
876
|
+
db
|
877
|
+
subclass.set_dataset(subclass.implicit_table_name)
|
878
|
+
end
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
1069
882
|
# A hash of instance variables to automatically set up in subclasses.
|
1070
|
-
#
|
1071
|
-
#
|
1072
|
-
#
|
883
|
+
# Keys are instance variable symbols, values should be:
|
884
|
+
# nil :: Assign directly from superclass to subclass (frozen objects)
|
885
|
+
# :dup :: Dup object when assigning from superclass to subclass (mutable objects)
|
886
|
+
# :hash_dup :: Assign hash with same keys, but dup all the values
|
887
|
+
# Proc :: Call with subclass to do the assignment
|
1073
888
|
def inherited_instance_variables
|
1074
|
-
|
889
|
+
{
|
890
|
+
:@cache_anonymous_models=>nil,
|
891
|
+
:@dataset_method_modules=>:dup,
|
892
|
+
:@dataset_module_class=>nil,
|
893
|
+
:@db=>nil,
|
894
|
+
:@default_set_fields_options=>:dup,
|
895
|
+
:@fast_instance_delete_sql=>nil,
|
896
|
+
:@fast_pk_lookup_sql=>nil,
|
897
|
+
:@plugins=>:dup,
|
898
|
+
:@primary_key=>nil,
|
899
|
+
:@raise_on_save_failure=>nil,
|
900
|
+
:@raise_on_typecast_failure=>nil,
|
901
|
+
:@require_modification=>nil,
|
902
|
+
:@require_valid_table=>nil,
|
903
|
+
:@restrict_primary_key=>nil,
|
904
|
+
:@setter_methods=>nil,
|
905
|
+
:@simple_pk=>nil,
|
906
|
+
:@simple_table=>nil,
|
907
|
+
:@strict_param_setting=>nil,
|
908
|
+
:@typecast_empty_string_to_nil=>nil,
|
909
|
+
:@typecast_on_assignment=>nil,
|
910
|
+
:@use_transactions=>nil
|
911
|
+
}
|
1075
912
|
end
|
1076
913
|
|
1077
914
|
# For the given opts hash and default name or :class option, add a
|
@@ -1096,6 +933,12 @@ module Sequel
|
|
1096
933
|
opts[:class_name] ||= '::' + ((name || '').split("::")[0..-2] + [camelize(default)]).join('::')
|
1097
934
|
end
|
1098
935
|
|
936
|
+
# Clear the setter_methods cache when a setter method is added.
|
937
|
+
def method_added(meth)
|
938
|
+
clear_setter_methods_cache if meth.to_s.end_with?('=')
|
939
|
+
super
|
940
|
+
end
|
941
|
+
|
1099
942
|
# Module that the class includes that holds methods the class adds for column accessors and
|
1100
943
|
# associations so that the methods can be overridden with +super+.
|
1101
944
|
def overridable_methods_module
|
@@ -1107,51 +950,12 @@ module Sequel
|
|
1107
950
|
# defined, the corresponding plugin required.
|
1108
951
|
def plugin_module(plugin)
|
1109
952
|
module_name = plugin.to_s.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
1110
|
-
|
1111
|
-
|
1112
|
-
Sequel::Plugins.const_get(module_name) == Sequel.const_get(module_name))
|
1113
|
-
begin
|
1114
|
-
require "sequel/plugins/#{plugin}"
|
1115
|
-
rescue LoadError => e
|
1116
|
-
begin
|
1117
|
-
require "sequel_#{plugin}"
|
1118
|
-
rescue LoadError => e2
|
1119
|
-
e.message << "; #{e2.message}"
|
1120
|
-
raise e
|
1121
|
-
end
|
1122
|
-
end
|
953
|
+
unless Sequel::Plugins.const_defined?(module_name, false)
|
954
|
+
require "sequel/plugins/#{plugin}"
|
1123
955
|
end
|
1124
956
|
Sequel::Plugins.const_get(module_name)
|
1125
957
|
end
|
1126
958
|
|
1127
|
-
# Check if the plugin module +plugin+ defines the constant named by +submod+.
|
1128
|
-
def plugin_module_defined?(plugin, submod)
|
1129
|
-
if RUBY_VERSION >= '1.9'
|
1130
|
-
plugin.const_defined?(submod, false)
|
1131
|
-
else
|
1132
|
-
# :nocov:
|
1133
|
-
plugin.const_defined?(submod)
|
1134
|
-
# :nocov:
|
1135
|
-
end
|
1136
|
-
end
|
1137
|
-
|
1138
|
-
# An hash of prepared argument values for the given arguments, with keys
|
1139
|
-
# starting at a. Used by the methods created by prepared_finder.
|
1140
|
-
def prepare_method_arg_hash(args)
|
1141
|
-
h = {}
|
1142
|
-
prepare_method_args('a', args.length).zip(args).each{|k, v| h[k] = v}
|
1143
|
-
h
|
1144
|
-
end
|
1145
|
-
|
1146
|
-
# An array of prepared statement argument names, of length n and starting with base.
|
1147
|
-
def prepare_method_args(base, n)
|
1148
|
-
(0...n).map do
|
1149
|
-
s = base.to_sym
|
1150
|
-
base = base.next
|
1151
|
-
s
|
1152
|
-
end
|
1153
|
-
end
|
1154
|
-
|
1155
959
|
# Find the row in the dataset that matches the primary key. Uses
|
1156
960
|
# a static SQL optimization if the table and primary key are simple.
|
1157
961
|
#
|
@@ -1165,10 +969,8 @@ module Sequel
|
|
1165
969
|
ds.literal_append(sql, pk)
|
1166
970
|
ds.fetch_rows(sql){|r| return ds.row_proc.call(r)}
|
1167
971
|
nil
|
1168
|
-
elsif dataset.joined_dataset?
|
1169
|
-
first_where(qualified_primary_key_hash(pk))
|
1170
972
|
else
|
1171
|
-
|
973
|
+
dataset.first(primary_key_hash(pk))
|
1172
974
|
end
|
1173
975
|
end
|
1174
976
|
|
@@ -1181,18 +983,17 @@ module Sequel
|
|
1181
983
|
# are used, or set it to nil if not used.
|
1182
984
|
def reset_fast_pk_lookup_sql
|
1183
985
|
@fast_pk_lookup_sql = if @simple_table && @simple_pk
|
1184
|
-
"SELECT * FROM
|
986
|
+
"SELECT * FROM #{@simple_table} WHERE #{@simple_pk} = ".freeze
|
1185
987
|
end
|
1186
988
|
@fast_instance_delete_sql = if @simple_table && @simple_pk
|
1187
|
-
"DELETE FROM
|
989
|
+
"DELETE FROM #{@simple_table} WHERE #{@simple_pk} = ".freeze
|
1188
990
|
end
|
1189
991
|
end
|
1190
992
|
|
1191
993
|
# Reset the instance dataset to a modified copy of the current dataset,
|
1192
994
|
# should be used whenever the model's dataset is modified.
|
1193
995
|
def reset_instance_dataset
|
1194
|
-
@
|
1195
|
-
@instance_dataset = @dataset.limit(1).naked if @dataset
|
996
|
+
@instance_dataset = @dataset.limit(1).naked.skip_limit_check if @dataset
|
1196
997
|
end
|
1197
998
|
|
1198
999
|
# Set the columns for this model and create accessor methods for each column.
|
@@ -1204,7 +1005,7 @@ module Sequel
|
|
1204
1005
|
|
1205
1006
|
# Set the dataset's row_proc to the current model.
|
1206
1007
|
def set_dataset_row_proc(ds)
|
1207
|
-
ds.
|
1008
|
+
ds.with_row_proc(self)
|
1208
1009
|
end
|
1209
1010
|
|
1210
1011
|
# Reset the fast primary key lookup SQL when the simple_pk value changes.
|
@@ -1228,38 +1029,43 @@ module Sequel
|
|
1228
1029
|
|
1229
1030
|
# Sequel::Model instance methods that implement basic model functionality.
|
1230
1031
|
#
|
1231
|
-
# * All of the
|
1032
|
+
# * All of the model before/after/around hooks are implemented as instance methods that are called
|
1232
1033
|
# by Sequel when the appropriate action occurs. For example, when destroying
|
1233
1034
|
# a model object, Sequel will call +around_destroy+, which will call +before_destroy+, do
|
1234
1035
|
# the destroy, and then call +after_destroy+.
|
1235
1036
|
# * The following instance_methods all call the class method of the same
|
1236
1037
|
# name: columns, db, primary_key, db_schema.
|
1237
|
-
# *
|
1238
|
-
#
|
1239
|
-
#
|
1240
|
-
#
|
1038
|
+
# * The following accessor methods are defined via metaprogramming:
|
1039
|
+
# raise_on_save_failure, raise_on_typecast_failure, require_modification,
|
1040
|
+
# strict_param_setting, typecast_empty_string_to_nil, typecast_on_assignment,
|
1041
|
+
# and use_transactions. The setter methods will change the setting for the
|
1042
|
+
# instance, and the getter methods will check for an instance setting, then
|
1043
|
+
# try the class setting if no instance setting has been set.
|
1241
1044
|
module InstanceMethods
|
1242
1045
|
HOOKS.each{|h| class_eval("def #{h}; end", __FILE__, __LINE__)}
|
1243
|
-
|
1046
|
+
[:around_create, :around_update, :around_save, :around_destroy, :around_validation].each{|h| class_eval("def #{h}; yield end", __FILE__, __LINE__)}
|
1244
1047
|
|
1245
1048
|
# Define instance method(s) that calls class method(s) of the
|
1246
1049
|
# same name. Replaces the construct:
|
1247
1050
|
#
|
1248
|
-
# define_method(meth){self.class.
|
1051
|
+
# define_method(meth){self.class.public_send(meth)}
|
1249
1052
|
[:columns, :db, :primary_key, :db_schema].each{|meth| class_eval("def #{meth}; self.class.#{meth} end", __FILE__, __LINE__)}
|
1250
1053
|
|
1251
1054
|
# Define instance method(s) that calls class method(s) of the
|
1252
1055
|
# same name, caching the result in an instance variable. Define
|
1253
1056
|
# standard attr_writer method for modifying that instance variable.
|
1254
|
-
|
1255
|
-
|
1057
|
+
[:typecast_empty_string_to_nil, :typecast_on_assignment, :strict_param_setting,
|
1058
|
+
:raise_on_save_failure, :raise_on_typecast_failure, :require_modification, :use_transactions].each do |meth|
|
1059
|
+
class_eval("def #{meth}; !defined?(@#{meth}) ? (frozen? ? self.class.#{meth} : (@#{meth} = self.class.#{meth})) : @#{meth} end", __FILE__, __LINE__)
|
1060
|
+
attr_writer(meth)
|
1061
|
+
end
|
1256
1062
|
|
1257
1063
|
# The hash of attribute values. Keys are symbols with the names of the
|
1258
1064
|
# underlying database columns. The returned hash is a reference to the
|
1259
1065
|
# receiver's values hash, and modifying it will also modify the receiver's
|
1260
1066
|
# values.
|
1261
1067
|
#
|
1262
|
-
# Artist.new(:
|
1068
|
+
# Artist.new(name: 'Bob').values # => {:name=>'Bob'}
|
1263
1069
|
# Artist[1].values # => {:id=>1, :name=>'Jim', ...}
|
1264
1070
|
attr_reader :values
|
1265
1071
|
alias to_hash values
|
@@ -1270,7 +1076,7 @@ module Sequel
|
|
1270
1076
|
# method names.
|
1271
1077
|
alias get_column_value send
|
1272
1078
|
|
1273
|
-
# Set the value of the column. Takes two
|
1079
|
+
# Set the value of the column. Takes two arguments. The first is a
|
1274
1080
|
# symbol or string argument for the column name, suffixed with =. The
|
1275
1081
|
# second is the value to set for the column. By default it calls send
|
1276
1082
|
# with the argument to set the value. This can be overridden if you have
|
@@ -1284,18 +1090,18 @@ module Sequel
|
|
1284
1090
|
# Arguments:
|
1285
1091
|
# values :: should be a hash to pass to set.
|
1286
1092
|
#
|
1287
|
-
# Artist.new(:
|
1093
|
+
# Artist.new(name: 'Bob')
|
1288
1094
|
#
|
1289
1095
|
# Artist.new do |a|
|
1290
1096
|
# a.name = 'Bob'
|
1291
1097
|
# end
|
1292
|
-
def initialize(values =
|
1098
|
+
def initialize(values = OPTS)
|
1293
1099
|
@values = {}
|
1294
1100
|
@new = true
|
1295
1101
|
@modified = true
|
1296
1102
|
initialize_set(values)
|
1297
|
-
|
1298
|
-
yield self if
|
1103
|
+
_clear_changed_columns(:initialize)
|
1104
|
+
yield self if defined?(yield)
|
1299
1105
|
end
|
1300
1106
|
|
1301
1107
|
# Returns value of the column's attribute.
|
@@ -1330,16 +1136,33 @@ module Sequel
|
|
1330
1136
|
eql?(obj)
|
1331
1137
|
end
|
1332
1138
|
|
1333
|
-
#
|
1334
|
-
#
|
1139
|
+
# Case equality. By default, checks equality of the primary key value, see
|
1140
|
+
# pk_equal?.
|
1335
1141
|
#
|
1336
|
-
# Artist[1] === Artist[1] # true
|
1337
|
-
# Artist.new === Artist.new # false
|
1338
|
-
# Artist[1].set(:name=>'Bob')
|
1142
|
+
# Artist[1] === Artist[1] # => true
|
1143
|
+
# Artist.new === Artist.new # => false
|
1144
|
+
# Artist[1].set(:name=>'Bob') === Artist[1] # => true
|
1339
1145
|
def ===(obj)
|
1340
|
-
|
1146
|
+
case pkv = pk
|
1147
|
+
when nil
|
1148
|
+
return false
|
1149
|
+
when Array
|
1150
|
+
return false if pkv.any?(&:nil?)
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
(obj.class == model) && (obj.pk == pkv)
|
1341
1154
|
end
|
1342
|
-
|
1155
|
+
|
1156
|
+
# If the receiver has a primary key value, returns true if the objects have
|
1157
|
+
# the same class and primary key value.
|
1158
|
+
# If the receiver's primary key value is nil or is an array containing
|
1159
|
+
# nil, returns false.
|
1160
|
+
#
|
1161
|
+
# Artist[1].pk_equal?(Artist[1]) # => true
|
1162
|
+
# Artist.new.pk_equal?(Artist.new) # => false
|
1163
|
+
# Artist[1].set(:name=>'Bob').pk_equal?(Artist[1]) # => true
|
1164
|
+
alias pk_equal? ===
|
1165
|
+
|
1343
1166
|
# class is defined in Object, but it is also a keyword,
|
1344
1167
|
# and since a lot of instance methods call class methods,
|
1345
1168
|
# this alias makes it so you can use model instead of
|
@@ -1371,9 +1194,9 @@ module Sequel
|
|
1371
1194
|
# a.name = 'Bob'
|
1372
1195
|
# a.changed_columns # => [:name]
|
1373
1196
|
def changed_columns
|
1374
|
-
|
1197
|
+
_changed_columns
|
1375
1198
|
end
|
1376
|
-
|
1199
|
+
|
1377
1200
|
# Deletes and returns +self+. Does not run destroy hooks.
|
1378
1201
|
# Look into using +destroy+ instead.
|
1379
1202
|
#
|
@@ -1386,11 +1209,8 @@ module Sequel
|
|
1386
1209
|
end
|
1387
1210
|
|
1388
1211
|
# Like delete but runs hooks before and after delete.
|
1389
|
-
#
|
1390
|
-
#
|
1391
|
-
# the item from the database and returns self. Uses a transaction
|
1392
|
-
# if use_transactions is true or if the :transaction option is given and
|
1393
|
-
# true.
|
1212
|
+
# Uses a transaction if use_transactions is true or if the
|
1213
|
+
# :transaction option is given and true.
|
1394
1214
|
#
|
1395
1215
|
# Artist[1].destroy # BEGIN; DELETE FROM artists WHERE (id = 1); COMMIT;
|
1396
1216
|
# # => #<Artist {:id=>1, ...}>
|
@@ -1448,13 +1268,13 @@ module Sequel
|
|
1448
1268
|
# Once an object is frozen, you cannot modify it's values, changed_columns,
|
1449
1269
|
# errors, or dataset.
|
1450
1270
|
def freeze
|
1451
|
-
values.freeze
|
1452
|
-
changed_columns.freeze
|
1453
1271
|
unless errors.frozen?
|
1454
1272
|
validate
|
1455
1273
|
errors.freeze
|
1456
1274
|
end
|
1457
|
-
|
1275
|
+
values.freeze
|
1276
|
+
_changed_columns.freeze
|
1277
|
+
this if !new? && model.primary_key
|
1458
1278
|
super
|
1459
1279
|
end
|
1460
1280
|
|
@@ -1462,9 +1282,9 @@ module Sequel
|
|
1462
1282
|
# the same class and values (if pk is nil).
|
1463
1283
|
#
|
1464
1284
|
# Artist[1].hash == Artist[1].hash # true
|
1465
|
-
# Artist[1].set(:
|
1285
|
+
# Artist[1].set(name: 'Bob').hash == Artist[1].hash # true
|
1466
1286
|
# Artist.new.hash == Artist.new.hash # true
|
1467
|
-
# Artist.new(:
|
1287
|
+
# Artist.new(name: 'Bob').hash == Artist.new.hash # false
|
1468
1288
|
def hash
|
1469
1289
|
case primary_key
|
1470
1290
|
when Array
|
@@ -1493,7 +1313,7 @@ module Sequel
|
|
1493
1313
|
# Returns the keys in +values+. May not include all column names.
|
1494
1314
|
#
|
1495
1315
|
# Artist.new.keys # => []
|
1496
|
-
# Artist.new(:
|
1316
|
+
# Artist.new(name: 'Bob').keys # => [:name]
|
1497
1317
|
# Artist[1].keys # => [:id, :name]
|
1498
1318
|
def keys
|
1499
1319
|
@values.keys
|
@@ -1517,11 +1337,11 @@ module Sequel
|
|
1517
1337
|
# a.update(:name=>'A')
|
1518
1338
|
# end
|
1519
1339
|
#
|
1520
|
-
#
|
1521
|
-
#
|
1522
|
-
#
|
1523
|
-
#
|
1524
|
-
#
|
1340
|
+
# a = Artist[2]
|
1341
|
+
# Artist.db.transaction do
|
1342
|
+
# a.lock!('FOR NO KEY UPDATE')
|
1343
|
+
# a.update(:name=>'B')
|
1344
|
+
# end
|
1525
1345
|
def lock!(style=:update)
|
1526
1346
|
_refresh(this.lock_style(style)) unless new?
|
1527
1347
|
self
|
@@ -1553,9 +1373,7 @@ module Sequel
|
|
1553
1373
|
# a.modified!(:name)
|
1554
1374
|
# a.name.gsub!(/[aeou]/, 'i')
|
1555
1375
|
def modified!(column=nil)
|
1556
|
-
|
1557
|
-
changed_columns << column
|
1558
|
-
end
|
1376
|
+
_add_changed_column(column) if column
|
1559
1377
|
@modified = true
|
1560
1378
|
end
|
1561
1379
|
|
@@ -1565,7 +1383,7 @@ module Sequel
|
|
1565
1383
|
#
|
1566
1384
|
# a = Artist[1]
|
1567
1385
|
# a.modified? # => false
|
1568
|
-
# a.set(:
|
1386
|
+
# a.set(name: 'Jim')
|
1569
1387
|
# a.modified? # => true
|
1570
1388
|
#
|
1571
1389
|
# If a column is given, specifically check if the given column has
|
@@ -1614,12 +1432,12 @@ module Sequel
|
|
1614
1432
|
model.primary_key_hash(pk)
|
1615
1433
|
end
|
1616
1434
|
|
1617
|
-
# Returns a hash mapping the receivers primary key column(s) to their values.
|
1435
|
+
# Returns a hash mapping the receivers qualified primary key column(s) to their values.
|
1618
1436
|
#
|
1619
1437
|
# Artist[1].qualified_pk_hash
|
1620
|
-
# # => {Sequel
|
1438
|
+
# # => {Sequel[:artists][:id]=>1}
|
1621
1439
|
# Artist[[1, 2]].qualified_pk_hash
|
1622
|
-
# # => {Sequel
|
1440
|
+
# # => {Sequel[:artists][:id1]=>1, Sequel[:artists][:id2]=>2}
|
1623
1441
|
def qualified_pk_hash(qualifier=model.table_name)
|
1624
1442
|
model.qualified_primary_key_hash(pk, qualifier)
|
1625
1443
|
end
|
@@ -1647,9 +1465,9 @@ module Sequel
|
|
1647
1465
|
# is valid and before hooks execute successfully. Fails if:
|
1648
1466
|
#
|
1649
1467
|
# * the record is not valid, or
|
1650
|
-
# * before_save
|
1651
|
-
# * the record is new and before_create
|
1652
|
-
# * the record is not new and before_update
|
1468
|
+
# * before_save calls cancel_action, or
|
1469
|
+
# * the record is new and before_create calls cancel_action, or
|
1470
|
+
# * the record is not new and before_update calls cancel_action.
|
1653
1471
|
#
|
1654
1472
|
# If +save+ fails and either raise_on_save_failure or the
|
1655
1473
|
# :raise_on_failure option is true, it raises ValidationFailed
|
@@ -1657,9 +1475,6 @@ module Sequel
|
|
1657
1475
|
#
|
1658
1476
|
# If it succeeds, it returns self.
|
1659
1477
|
#
|
1660
|
-
# You can provide an optional list of columns to update, in which
|
1661
|
-
# case it only updates those columns, or a options hash.
|
1662
|
-
#
|
1663
1478
|
# Takes the following options:
|
1664
1479
|
#
|
1665
1480
|
# :changed :: save all changed columns, instead of all columns or the columns given
|
@@ -1674,12 +1489,9 @@ module Sequel
|
|
1674
1489
|
def save(opts=OPTS)
|
1675
1490
|
raise Sequel::Error, "can't save frozen object" if frozen?
|
1676
1491
|
set_server(opts[:server]) if opts[:server]
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1680
|
-
raise(ValidationFailed.new(self)) if raise_on_failure?(opts)
|
1681
|
-
return
|
1682
|
-
end
|
1492
|
+
unless _save_valid?(opts)
|
1493
|
+
raise(validation_failed_error) if raise_on_failure?(opts)
|
1494
|
+
return
|
1683
1495
|
end
|
1684
1496
|
checked_save_failure(opts){checked_transaction(opts){_save(opts)}}
|
1685
1497
|
end
|
@@ -1702,22 +1514,12 @@ module Sequel
|
|
1702
1514
|
# a setter method (or ignoring it if <tt>strict_param_setting = false</tt>).
|
1703
1515
|
# Does not save the record.
|
1704
1516
|
#
|
1705
|
-
# artist.set(:
|
1517
|
+
# artist.set(name: 'Jim')
|
1706
1518
|
# artist.name # => 'Jim'
|
1707
1519
|
def set(hash)
|
1708
1520
|
set_restricted(hash, :default)
|
1709
1521
|
end
|
1710
1522
|
|
1711
|
-
# Set all values using the entries in the hash, ignoring any setting of
|
1712
|
-
# allowed_columns in the model.
|
1713
|
-
#
|
1714
|
-
# Artist.set_allowed_columns(:num_albums)
|
1715
|
-
# artist.set_all(:name=>'Jim')
|
1716
|
-
# artist.name # => 'Jim'
|
1717
|
-
def set_all(hash)
|
1718
|
-
set_restricted(hash, :all)
|
1719
|
-
end
|
1720
|
-
|
1721
1523
|
# For each of the fields in the given array +fields+, call the setter
|
1722
1524
|
# method with the value of that +hash+ entry for the field. Returns self.
|
1723
1525
|
#
|
@@ -1730,43 +1532,36 @@ module Sequel
|
|
1730
1532
|
#
|
1731
1533
|
# Examples:
|
1732
1534
|
#
|
1733
|
-
# artist.set_fields({:
|
1535
|
+
# artist.set_fields({name: 'Jim'}, [:name])
|
1734
1536
|
# artist.name # => 'Jim'
|
1735
1537
|
#
|
1736
|
-
# artist.set_fields({:
|
1538
|
+
# artist.set_fields({hometown: 'LA'}, [:name])
|
1737
1539
|
# artist.name # => nil
|
1738
1540
|
# artist.hometown # => 'Sac'
|
1739
1541
|
#
|
1740
1542
|
# artist.name # => 'Jim'
|
1741
|
-
# artist.set_fields({}, [:name], :
|
1543
|
+
# artist.set_fields({}, [:name], missing: :skip)
|
1742
1544
|
# artist.name # => 'Jim'
|
1743
1545
|
#
|
1744
1546
|
# artist.name # => 'Jim'
|
1745
|
-
# artist.set_fields({}, [:name], :
|
1547
|
+
# artist.set_fields({}, [:name], missing: :raise)
|
1746
1548
|
# # Sequel::Error raised
|
1747
1549
|
def set_fields(hash, fields, opts=nil)
|
1748
1550
|
opts = if opts
|
1749
|
-
|
1551
|
+
model.default_set_fields_options.merge(opts)
|
1750
1552
|
else
|
1751
1553
|
model.default_set_fields_options
|
1752
1554
|
end
|
1753
1555
|
|
1754
|
-
case opts[:missing]
|
1755
|
-
when :skip
|
1556
|
+
case missing = opts[:missing]
|
1557
|
+
when :skip, :raise
|
1558
|
+
do_raise = true if missing == :raise
|
1756
1559
|
fields.each do |f|
|
1757
1560
|
if hash.has_key?(f)
|
1758
1561
|
set_column_value("#{f}=", hash[f])
|
1759
1562
|
elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
|
1760
1563
|
set_column_value("#{sf}=", hash[sf])
|
1761
|
-
|
1762
|
-
end
|
1763
|
-
when :raise
|
1764
|
-
fields.each do |f|
|
1765
|
-
if hash.has_key?(f)
|
1766
|
-
set_column_value("#{f}=", hash[f])
|
1767
|
-
elsif f.is_a?(Symbol) && hash.has_key?(sf = f.to_s)
|
1768
|
-
set_column_value("#{sf}=", hash[sf])
|
1769
|
-
else
|
1564
|
+
elsif do_raise
|
1770
1565
|
raise(Sequel::Error, "missing field in hash: #{f.inspect} not in #{hash.inspect}")
|
1771
1566
|
end
|
1772
1567
|
end
|
@@ -1776,31 +1571,28 @@ module Sequel
|
|
1776
1571
|
self
|
1777
1572
|
end
|
1778
1573
|
|
1779
|
-
# Set the values using the entries in the hash, only if the key
|
1780
|
-
# is included in only. It may be a better idea to use +set_fields+
|
1781
|
-
# instead of this method.
|
1782
|
-
#
|
1783
|
-
# artist.set_only({:name=>'Jim'}, :name)
|
1784
|
-
# artist.name # => 'Jim'
|
1785
|
-
#
|
1786
|
-
# artist.set_only({:hometown=>'LA'}, :name) # Raise Error
|
1787
|
-
def set_only(hash, *only)
|
1788
|
-
set_restricted(hash, only.flatten)
|
1789
|
-
end
|
1790
|
-
|
1791
1574
|
# Set the shard that this object is tied to. Returns self.
|
1792
1575
|
def set_server(s)
|
1793
1576
|
@server = s
|
1794
|
-
@this
|
1577
|
+
@this = @this.server(s) if @this
|
1795
1578
|
self
|
1796
1579
|
end
|
1797
1580
|
|
1798
1581
|
# Clear the setter_methods cache when a method is added
|
1799
1582
|
def singleton_method_added(meth)
|
1800
|
-
@singleton_setter_added = true if meth.to_s
|
1583
|
+
@singleton_setter_added = true if meth.to_s.end_with?('=')
|
1801
1584
|
super
|
1802
1585
|
end
|
1803
1586
|
|
1587
|
+
# Skip all validation of the object on the next call to #save,
|
1588
|
+
# including the running of validation hooks. This is designed for
|
1589
|
+
# and should only be used in cases where #valid? is called before
|
1590
|
+
# saving and the <tt>validate: false</tt> option cannot be passed to
|
1591
|
+
# #save.
|
1592
|
+
def skip_validation_on_next_save!
|
1593
|
+
@skip_validation_on_next_save = true
|
1594
|
+
end
|
1595
|
+
|
1804
1596
|
# Returns (naked) dataset that should return only this instance.
|
1805
1597
|
#
|
1806
1598
|
# Artist[1].this
|
@@ -1808,57 +1600,29 @@ module Sequel
|
|
1808
1600
|
def this
|
1809
1601
|
return @this if @this
|
1810
1602
|
raise Error, "No dataset for model #{model}" unless ds = model.instance_dataset
|
1811
|
-
|
1812
|
-
cond = if ds.joined_dataset?
|
1813
|
-
qualified_pk_hash
|
1814
|
-
else
|
1815
|
-
pk_hash
|
1816
|
-
end
|
1817
|
-
|
1818
|
-
@this = use_server(ds.where(cond))
|
1603
|
+
@this = use_server(ds.where(pk_hash))
|
1819
1604
|
end
|
1820
1605
|
|
1821
1606
|
# Runs #set with the passed hash and then runs save_changes.
|
1822
1607
|
#
|
1823
|
-
# artist.update(:
|
1608
|
+
# artist.update(name: 'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
1824
1609
|
def update(hash)
|
1825
1610
|
update_restricted(hash, :default)
|
1826
1611
|
end
|
1827
1612
|
|
1828
|
-
# Update
|
1829
|
-
#
|
1613
|
+
# Update the instance's values by calling set_fields with the arguments, then
|
1614
|
+
# calls save_changes.
|
1830
1615
|
#
|
1831
|
-
#
|
1832
|
-
# artist.update_all(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
1833
|
-
def update_all(hash)
|
1834
|
-
update_restricted(hash, :all)
|
1835
|
-
end
|
1836
|
-
|
1837
|
-
# Update the instances values by calling +set_fields+ with the arguments, then
|
1838
|
-
# saves any changes to the record. Returns self.
|
1839
|
-
#
|
1840
|
-
# artist.update_fields({:name=>'Jim'}, [:name])
|
1616
|
+
# artist.update_fields({name: 'Jim'}, [:name])
|
1841
1617
|
# # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
1842
1618
|
#
|
1843
|
-
# artist.update_fields({:
|
1619
|
+
# artist.update_fields({hometown: 'LA'}, [:name])
|
1844
1620
|
# # UPDATE artists SET name = NULL WHERE (id = 1)
|
1845
1621
|
def update_fields(hash, fields, opts=nil)
|
1846
1622
|
set_fields(hash, fields, opts)
|
1847
1623
|
save_changes
|
1848
1624
|
end
|
1849
1625
|
|
1850
|
-
# Update the values using the entries in the hash, only if the key
|
1851
|
-
# is included in only. It may be a better idea to use +update_fields+
|
1852
|
-
# instead of this method.
|
1853
|
-
#
|
1854
|
-
# artist.update_only({:name=>'Jim'}, :name)
|
1855
|
-
# # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
1856
|
-
#
|
1857
|
-
# artist.update_only({:hometown=>'LA'}, :name) # Raise Error
|
1858
|
-
def update_only(hash, *only)
|
1859
|
-
update_restricted(hash, only.flatten)
|
1860
|
-
end
|
1861
|
-
|
1862
1626
|
# Validates the object. If the object is invalid, errors should be added
|
1863
1627
|
# to the errors attribute. By default, does nothing, as all models
|
1864
1628
|
# are valid by default. See the {"Model Validations" guide}[rdoc-ref:doc/validations.rdoc].
|
@@ -1870,51 +1634,35 @@ module Sequel
|
|
1870
1634
|
|
1871
1635
|
# Validates the object and returns true if no errors are reported.
|
1872
1636
|
#
|
1873
|
-
# artist(:
|
1874
|
-
# artist(:
|
1637
|
+
# artist.set(name: 'Valid').valid? # => true
|
1638
|
+
# artist.set(name: 'Invalid').valid? # => false
|
1875
1639
|
# artist.errors.full_messages # => ['name cannot be Invalid']
|
1876
1640
|
def valid?(opts = OPTS)
|
1877
|
-
|
1878
|
-
|
1641
|
+
_valid?(opts)
|
1642
|
+
rescue HookFailed
|
1643
|
+
false
|
1879
1644
|
end
|
1880
1645
|
|
1881
1646
|
private
|
1882
1647
|
|
1883
|
-
#
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
@new = false
|
1888
|
-
@was_new = true
|
1889
|
-
end
|
1890
|
-
|
1891
|
-
# Run code after around_save returns, before calling after_commit.
|
1892
|
-
# This is only a temporary API, it should not be overridden by external code.
|
1893
|
-
def _after_save(pk)
|
1894
|
-
if @was_new
|
1895
|
-
@was_new = nil
|
1896
|
-
pk ? _save_refresh : changed_columns.clear
|
1897
|
-
else
|
1898
|
-
@columns_updated = nil
|
1899
|
-
end
|
1900
|
-
@modified = false
|
1648
|
+
# Add a column as a changed column.
|
1649
|
+
def _add_changed_column(column)
|
1650
|
+
cc = _changed_columns
|
1651
|
+
cc << column unless cc.include?(column)
|
1901
1652
|
end
|
1902
1653
|
|
1903
|
-
#
|
1904
|
-
|
1905
|
-
|
1906
|
-
@this = nil
|
1654
|
+
# Internal changed_columns method that just returns stored array.
|
1655
|
+
def _changed_columns
|
1656
|
+
@changed_columns ||= []
|
1907
1657
|
end
|
1908
1658
|
|
1909
|
-
#
|
1910
|
-
#
|
1911
|
-
#
|
1912
|
-
|
1913
|
-
|
1914
|
-
# if this returns false.
|
1915
|
-
def _before_validation
|
1659
|
+
# Clear the changed columns. Reason is the reason for clearing
|
1660
|
+
# the columns, and should be one of: :initialize, :refresh, :create
|
1661
|
+
# or :update.
|
1662
|
+
def _clear_changed_columns(_reason)
|
1663
|
+
_changed_columns.clear
|
1916
1664
|
end
|
1917
|
-
|
1665
|
+
|
1918
1666
|
# Do the deletion of the object's dataset, and check that the row
|
1919
1667
|
# was actually deleted.
|
1920
1668
|
def _delete
|
@@ -1923,7 +1671,7 @@ module Sequel
|
|
1923
1671
|
n
|
1924
1672
|
end
|
1925
1673
|
|
1926
|
-
# The dataset to use when deleting the object.
|
1674
|
+
# The dataset to use when deleting the object. The same as the object's
|
1927
1675
|
# dataset by default.
|
1928
1676
|
def _delete_dataset
|
1929
1677
|
this
|
@@ -1945,18 +1693,14 @@ module Sequel
|
|
1945
1693
|
# Internal destroy method, separted from destroy to
|
1946
1694
|
# allow running inside a transaction
|
1947
1695
|
def _destroy(opts)
|
1948
|
-
sh = {:server=>this_server}
|
1949
|
-
db.after_rollback(sh){after_destroy_rollback} if uacr = use_after_commit_rollback
|
1950
1696
|
called = false
|
1951
1697
|
around_destroy do
|
1952
1698
|
called = true
|
1953
|
-
|
1699
|
+
before_destroy
|
1954
1700
|
_destroy_delete
|
1955
1701
|
after_destroy
|
1956
|
-
true
|
1957
1702
|
end
|
1958
1703
|
raise_hook_failure(:around_destroy) unless called
|
1959
|
-
db.after_commit(sh){after_destroy_commit} if uacr
|
1960
1704
|
self
|
1961
1705
|
end
|
1962
1706
|
|
@@ -1971,8 +1715,8 @@ module Sequel
|
|
1971
1715
|
# the record should be refreshed from the database.
|
1972
1716
|
def _insert
|
1973
1717
|
ds = _insert_dataset
|
1974
|
-
if _use_insert_select?(ds) && (h = _insert_select_raw(ds))
|
1975
|
-
_save_set_values(h)
|
1718
|
+
if _use_insert_select?(ds) && !(h = _insert_select_raw(ds)).nil?
|
1719
|
+
_save_set_values(h) if h
|
1976
1720
|
nil
|
1977
1721
|
else
|
1978
1722
|
iid = _insert_raw(ds)
|
@@ -2003,20 +1747,28 @@ module Sequel
|
|
2003
1747
|
|
2004
1748
|
# The values hash to use when inserting a new record.
|
2005
1749
|
alias _insert_values values
|
1750
|
+
private :_insert_values
|
2006
1751
|
|
2007
1752
|
# Refresh using a particular dataset, used inside save to make sure the same server
|
2008
1753
|
# is used for reading newly inserted values from the database
|
2009
1754
|
def _refresh(dataset)
|
2010
1755
|
_refresh_set_values(_refresh_get(dataset) || raise(NoExistingObject, "Record not found"))
|
2011
|
-
|
1756
|
+
_clear_changed_columns(:refresh)
|
2012
1757
|
end
|
2013
1758
|
|
2014
1759
|
# Get the row of column data from the database.
|
2015
1760
|
def _refresh_get(dataset)
|
2016
|
-
dataset.
|
1761
|
+
if (sql = model.fast_pk_lookup_sql) && !dataset.opts[:lock]
|
1762
|
+
sql = sql.dup
|
1763
|
+
ds = use_server(dataset)
|
1764
|
+
ds.literal_append(sql, pk)
|
1765
|
+
ds.with_sql_first(sql)
|
1766
|
+
else
|
1767
|
+
dataset.first
|
1768
|
+
end
|
2017
1769
|
end
|
2018
1770
|
|
2019
|
-
# Set the
|
1771
|
+
# Set the values to the given hash after refreshing.
|
2020
1772
|
def _refresh_set_values(h)
|
2021
1773
|
@values = h
|
2022
1774
|
end
|
@@ -2024,20 +1776,22 @@ module Sequel
|
|
2024
1776
|
# Internal version of save, split from save to allow running inside
|
2025
1777
|
# it's own transaction.
|
2026
1778
|
def _save(opts)
|
2027
|
-
sh = {:server=>this_server}
|
2028
|
-
db.after_rollback(sh){after_rollback} if uacr = use_after_commit_rollback
|
2029
1779
|
pk = nil
|
2030
1780
|
called_save = false
|
2031
1781
|
called_cu = false
|
2032
1782
|
around_save do
|
2033
1783
|
called_save = true
|
2034
|
-
|
1784
|
+
before_save
|
1785
|
+
|
2035
1786
|
if new?
|
2036
1787
|
around_create do
|
2037
1788
|
called_cu = true
|
2038
|
-
|
1789
|
+
before_create
|
2039
1790
|
pk = _insert
|
2040
|
-
|
1791
|
+
@this = nil
|
1792
|
+
@new = false
|
1793
|
+
@modified = false
|
1794
|
+
pk ? _save_refresh : _clear_changed_columns(:create)
|
2041
1795
|
after_create
|
2042
1796
|
true
|
2043
1797
|
end
|
@@ -2045,22 +1799,23 @@ module Sequel
|
|
2045
1799
|
else
|
2046
1800
|
around_update do
|
2047
1801
|
called_cu = true
|
2048
|
-
|
1802
|
+
before_update
|
2049
1803
|
columns = opts[:columns]
|
2050
1804
|
if columns.nil?
|
2051
|
-
|
2052
|
-
|
1805
|
+
columns_updated = if opts[:changed]
|
1806
|
+
_save_update_changed_colums_hash
|
2053
1807
|
else
|
2054
1808
|
_save_update_all_columns_hash
|
2055
1809
|
end
|
2056
|
-
|
1810
|
+
_clear_changed_columns(:update)
|
2057
1811
|
else # update only the specified columns
|
2058
1812
|
columns = Array(columns)
|
2059
|
-
|
2060
|
-
|
1813
|
+
columns_updated = @values.reject{|k, v| !columns.include?(k)}
|
1814
|
+
_changed_columns.reject!{|c| columns.include?(c)}
|
2061
1815
|
end
|
2062
|
-
_update_columns(
|
2063
|
-
|
1816
|
+
_update_columns(columns_updated)
|
1817
|
+
@this = nil
|
1818
|
+
@modified = false
|
2064
1819
|
after_update
|
2065
1820
|
true
|
2066
1821
|
end
|
@@ -2070,17 +1825,15 @@ module Sequel
|
|
2070
1825
|
true
|
2071
1826
|
end
|
2072
1827
|
raise_hook_failure(:around_save) unless called_save
|
2073
|
-
_after_save(pk)
|
2074
|
-
db.after_commit(sh){after_commit} if uacr
|
2075
1828
|
self
|
2076
1829
|
end
|
2077
|
-
|
1830
|
+
|
2078
1831
|
# Refresh the object after saving it, used to get
|
2079
1832
|
# default values of all columns. Separated from _save so it
|
2080
1833
|
# can be overridden to avoid the refresh.
|
2081
1834
|
def _save_refresh
|
2082
1835
|
_save_set_values(_refresh_get(this.server?(:default)) || raise(NoExistingObject, "Record not found"))
|
2083
|
-
|
1836
|
+
_clear_changed_columns(:create)
|
2084
1837
|
end
|
2085
1838
|
|
2086
1839
|
# Set values to the provided hash. Called after a create,
|
@@ -2097,10 +1850,32 @@ module Sequel
|
|
2097
1850
|
# to their existing values.
|
2098
1851
|
def _save_update_all_columns_hash
|
2099
1852
|
v = Hash[@values]
|
2100
|
-
|
1853
|
+
cc = changed_columns
|
1854
|
+
Array(primary_key).each{|x| v.delete(x) unless cc.include?(x)}
|
2101
1855
|
v
|
2102
1856
|
end
|
2103
1857
|
|
1858
|
+
# Return a hash of values used when saving changed columns of an
|
1859
|
+
# existing object. Defaults to all of the objects current values
|
1860
|
+
# that are recorded as modified.
|
1861
|
+
def _save_update_changed_colums_hash
|
1862
|
+
cc = changed_columns
|
1863
|
+
@values.reject{|k,v| !cc.include?(k)}
|
1864
|
+
end
|
1865
|
+
|
1866
|
+
# Validate the object if validating on save. Skips validation
|
1867
|
+
# completely (including validation hooks) if
|
1868
|
+
# skip_validation_on_save! has been called on the object,
|
1869
|
+
# resetting the flag so that future saves will validate.
|
1870
|
+
def _save_valid?(opts)
|
1871
|
+
if @skip_validation_on_next_save
|
1872
|
+
@skip_validation_on_next_save = false
|
1873
|
+
return true
|
1874
|
+
end
|
1875
|
+
|
1876
|
+
checked_save_failure(opts){_valid?(opts)}
|
1877
|
+
end
|
1878
|
+
|
2104
1879
|
# Call _update with the given columns, if any are present.
|
2105
1880
|
# Plugins can override this method in order to update with
|
2106
1881
|
# additional columns, even when the column hash is initially empty.
|
@@ -2132,38 +1907,25 @@ module Sequel
|
|
2132
1907
|
(!ds.opts[:select] || ds.opts[:returning]) && ds.supports_insert_select?
|
2133
1908
|
end
|
2134
1909
|
|
2135
|
-
# Internal validation method
|
2136
|
-
|
2137
|
-
# +false+, +false+ will be returned instead.
|
2138
|
-
def _valid?(raise_errors, opts)
|
1910
|
+
# Internal validation method, running validation hooks.
|
1911
|
+
def _valid?(opts)
|
2139
1912
|
return errors.empty? if frozen?
|
2140
1913
|
errors.clear
|
2141
1914
|
called = false
|
2142
|
-
|
1915
|
+
skip_validate = opts[:validate] == false
|
2143
1916
|
around_validation do
|
2144
1917
|
called = true
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
else
|
2149
|
-
error = true
|
2150
|
-
end
|
2151
|
-
false
|
2152
|
-
else
|
2153
|
-
validate
|
2154
|
-
after_validation
|
2155
|
-
errors.empty?
|
2156
|
-
end
|
1918
|
+
before_validation
|
1919
|
+
validate unless skip_validate
|
1920
|
+
after_validation
|
2157
1921
|
end
|
2158
|
-
|
2159
|
-
if
|
2160
|
-
|
2161
|
-
|
2162
|
-
else
|
2163
|
-
false
|
2164
|
-
end
|
2165
|
-
else
|
1922
|
+
|
1923
|
+
return true if skip_validate
|
1924
|
+
|
1925
|
+
if called
|
2166
1926
|
errors.empty?
|
1927
|
+
else
|
1928
|
+
raise_hook_failure(:around_validation)
|
2167
1929
|
end
|
2168
1930
|
end
|
2169
1931
|
|
@@ -2188,8 +1950,7 @@ module Sequel
|
|
2188
1950
|
|
2189
1951
|
# Change the value of the column to given value, recording the change.
|
2190
1952
|
def change_column_value(column, value)
|
2191
|
-
|
2192
|
-
cc << column unless cc.include?(column)
|
1953
|
+
_add_changed_column(column)
|
2193
1954
|
@values[column] = value
|
2194
1955
|
end
|
2195
1956
|
|
@@ -2198,24 +1959,17 @@ module Sequel
|
|
2198
1959
|
Errors
|
2199
1960
|
end
|
2200
1961
|
|
2201
|
-
|
2202
|
-
|
2203
|
-
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
def clone
|
2213
|
-
o = dup
|
2214
|
-
o.freeze if frozen?
|
2215
|
-
o
|
2216
|
-
end
|
2217
|
-
public :clone
|
2218
|
-
# :nocov:
|
1962
|
+
# A HookFailed exception for the given message tied to the current instance.
|
1963
|
+
def hook_failed_error(msg)
|
1964
|
+
HookFailed.new(msg, self)
|
1965
|
+
end
|
1966
|
+
|
1967
|
+
# Clone constructor -- freeze internal data structures if the original's
|
1968
|
+
# are frozen.
|
1969
|
+
def initialize_clone(other)
|
1970
|
+
super
|
1971
|
+
freeze if other.frozen?
|
1972
|
+
self
|
2219
1973
|
end
|
2220
1974
|
|
2221
1975
|
# Copy constructor -- Duplicate internal data structures.
|
@@ -2224,7 +1978,6 @@ module Sequel
|
|
2224
1978
|
@values = Hash[@values]
|
2225
1979
|
@changed_columns = @changed_columns.dup if @changed_columns
|
2226
1980
|
@errors = @errors.dup if @errors
|
2227
|
-
@this = @this.dup if @this
|
2228
1981
|
self
|
2229
1982
|
end
|
2230
1983
|
|
@@ -2260,9 +2013,9 @@ module Sequel
|
|
2260
2013
|
"a hook failed"
|
2261
2014
|
end
|
2262
2015
|
|
2263
|
-
raise
|
2016
|
+
raise hook_failed_error(msg)
|
2264
2017
|
end
|
2265
|
-
|
2018
|
+
|
2266
2019
|
# Get the ruby class or classes related to the given column's type.
|
2267
2020
|
def schema_type_class(column)
|
2268
2021
|
if (sch = db_schema[column]) && (type = sch[:type])
|
@@ -2303,19 +2056,13 @@ module Sequel
|
|
2303
2056
|
# :all :: Allow setting all setters, except those specifically restricted (such as ==).
|
2304
2057
|
# Array :: Only allow setting of columns in the given array.
|
2305
2058
|
def setter_methods(type)
|
2306
|
-
if type == :default
|
2307
|
-
|
2308
|
-
return model.setter_methods
|
2309
|
-
end
|
2059
|
+
if type == :default && !@singleton_setter_added
|
2060
|
+
return model.setter_methods
|
2310
2061
|
end
|
2311
2062
|
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
meths = methods.collect(&:to_s).grep(SETTER_METHOD_REGEXP) - RESTRICTED_SETTER_METHODS
|
2316
|
-
meths -= Array(primary_key).map{|x| "#{x}="} if type != :all && primary_key && model.restrict_primary_key?
|
2317
|
-
meths
|
2318
|
-
end
|
2063
|
+
meths = methods.map(&:to_s).select{|l| l.end_with?('=')} - RESTRICTED_SETTER_METHODS
|
2064
|
+
meths -= Array(primary_key).map{|x| "#{x}="} if primary_key && model.restrict_primary_key?
|
2065
|
+
meths
|
2319
2066
|
end
|
2320
2067
|
|
2321
2068
|
# The server/shard that the model object's dataset uses, or :default if the
|
@@ -2361,22 +2108,28 @@ module Sequel
|
|
2361
2108
|
def use_transaction?(opts = OPTS)
|
2362
2109
|
opts.fetch(:transaction, use_transactions)
|
2363
2110
|
end
|
2111
|
+
|
2112
|
+
# An ValidationFailed exception instance to raise for this instance.
|
2113
|
+
def validation_failed_error
|
2114
|
+
ValidationFailed.new(self)
|
2115
|
+
end
|
2364
2116
|
end
|
2365
2117
|
|
2366
|
-
#
|
2367
|
-
# the call to set_dataset.
|
2118
|
+
# DatasetMethods contains methods that all model datasets have.
|
2368
2119
|
module DatasetMethods
|
2369
2120
|
# The model class associated with this dataset
|
2370
2121
|
#
|
2371
2122
|
# Artist.dataset.model # => Artist
|
2372
|
-
|
2123
|
+
def model
|
2124
|
+
@opts[:model]
|
2125
|
+
end
|
2373
2126
|
|
2374
2127
|
# Assume if a single integer is given that it is a lookup by primary
|
2375
2128
|
# key, and call with_pk with the argument.
|
2376
2129
|
#
|
2377
2130
|
# Artist.dataset[1] # SELECT * FROM artists WHERE (id = 1) LIMIT 1
|
2378
2131
|
def [](*args)
|
2379
|
-
if args.length == 1 && (i = args
|
2132
|
+
if args.length == 1 && (i = args[0]) && i.is_a?(Integer)
|
2380
2133
|
with_pk(i)
|
2381
2134
|
else
|
2382
2135
|
super
|
@@ -2397,58 +2150,14 @@ module Sequel
|
|
2397
2150
|
model.use_transactions ? @db.transaction(:server=>opts[:server], &pr) : pr.call
|
2398
2151
|
end
|
2399
2152
|
|
2400
|
-
# Allow Sequel::Model classes to be used as dataset arguments when graphing:
|
2401
|
-
#
|
2402
|
-
# Artist.graph(Album, :artist_id=>id)
|
2403
|
-
# # SELECT artists.id, artists.name, albums.id AS albums_id, albums.artist_id, albums.name AS albums_name
|
2404
|
-
# # FROM artists LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
|
2405
|
-
def graph(table, *args, &block)
|
2406
|
-
if table.is_a?(Class) && table < Sequel::Model
|
2407
|
-
super(table.dataset, *args, &block)
|
2408
|
-
else
|
2409
|
-
super
|
2410
|
-
end
|
2411
|
-
end
|
2412
|
-
|
2413
|
-
# Handle Sequel::Model instances when inserting, using the model instance's
|
2414
|
-
# values for the insert, unless the model instance can be used directly in
|
2415
|
-
# SQL.
|
2416
|
-
#
|
2417
|
-
# Album.insert(Album.load(:name=>'A'))
|
2418
|
-
# # INSERT INTO albums (name) VALUES ('A')
|
2419
|
-
def insert_sql(*values)
|
2420
|
-
if values.size == 1 && (v = values.at(0)).is_a?(Sequel::Model) && !v.respond_to?(:sql_literal_append)
|
2421
|
-
super(v.to_hash)
|
2422
|
-
else
|
2423
|
-
super
|
2424
|
-
end
|
2425
|
-
end
|
2426
|
-
|
2427
|
-
# Allow Sequel::Model classes to be used as table name arguments in dataset
|
2428
|
-
# join methods:
|
2429
|
-
#
|
2430
|
-
# Artist.join(Album, :artist_id=>id)
|
2431
|
-
# # SELECT * FROM artists INNER JOIN albums ON (albums.artist_id = artists.id)
|
2432
|
-
def join_table(type, table, *args, &block)
|
2433
|
-
if table.is_a?(Class) && table < Sequel::Model
|
2434
|
-
if table.dataset.simple_select_all?
|
2435
|
-
super(type, table.table_name, *args, &block)
|
2436
|
-
else
|
2437
|
-
super(type, table.dataset, *args, &block)
|
2438
|
-
end
|
2439
|
-
else
|
2440
|
-
super
|
2441
|
-
end
|
2442
|
-
end
|
2443
|
-
|
2444
2153
|
# If there is no order already defined on this dataset, order it by
|
2445
2154
|
# the primary key and call last.
|
2446
2155
|
#
|
2447
2156
|
# Album.last
|
2448
2157
|
# # SELECT * FROM albums ORDER BY id DESC LIMIT 1
|
2449
2158
|
def last(*a, &block)
|
2450
|
-
if
|
2451
|
-
|
2159
|
+
if ds = _primary_key_order
|
2160
|
+
ds.last(*a, &block)
|
2452
2161
|
else
|
2453
2162
|
super
|
2454
2163
|
end
|
@@ -2463,22 +2172,22 @@ module Sequel
|
|
2463
2172
|
# # SELECT * FROM albums ORDER BY id LIMIT 1000 OFFSET 2000
|
2464
2173
|
# # ...
|
2465
2174
|
def paged_each(*a, &block)
|
2466
|
-
if
|
2467
|
-
|
2175
|
+
if ds = _primary_key_order
|
2176
|
+
ds.paged_each(*a, &block)
|
2468
2177
|
else
|
2469
2178
|
super
|
2470
2179
|
end
|
2471
2180
|
end
|
2472
2181
|
|
2473
|
-
# This allows you to call +
|
2182
|
+
# This allows you to call +as_hash+ without any arguments, which will
|
2474
2183
|
# result in a hash with the primary key value being the key and the
|
2475
2184
|
# model object being the value.
|
2476
2185
|
#
|
2477
|
-
# Artist.dataset.
|
2186
|
+
# Artist.dataset.as_hash # SELECT * FROM artists
|
2478
2187
|
# # => {1=>#<Artist {:id=>1, ...}>,
|
2479
2188
|
# # 2=>#<Artist {:id=>2, ...}>,
|
2480
2189
|
# # ...}
|
2481
|
-
def
|
2190
|
+
def as_hash(key_column=nil, value_column=nil, opts=OPTS)
|
2482
2191
|
if key_column
|
2483
2192
|
super
|
2484
2193
|
else
|
@@ -2487,6 +2196,11 @@ module Sequel
|
|
2487
2196
|
end
|
2488
2197
|
end
|
2489
2198
|
|
2199
|
+
# Alias of as_hash for backwards compatibility.
|
2200
|
+
def to_hash(*a)
|
2201
|
+
as_hash(*a)
|
2202
|
+
end
|
2203
|
+
|
2490
2204
|
# Given a primary key value, return the first record in the dataset with that primary key
|
2491
2205
|
# value. If no records matches, returns nil.
|
2492
2206
|
#
|
@@ -2498,7 +2212,11 @@ module Sequel
|
|
2498
2212
|
# Artist.dataset.with_pk([1, 2])
|
2499
2213
|
# # SELECT * FROM artists WHERE ((artists.id1 = 1) AND (artists.id2 = 2)) LIMIT 1
|
2500
2214
|
def with_pk(pk)
|
2501
|
-
|
2215
|
+
if pk && (loader = _with_pk_loader)
|
2216
|
+
loader.first(*pk)
|
2217
|
+
else
|
2218
|
+
first(model.qualified_primary_key_hash(pk))
|
2219
|
+
end
|
2502
2220
|
end
|
2503
2221
|
|
2504
2222
|
# Same as with_pk, but raises NoMatchingRow instead of returning nil if no
|
@@ -2506,10 +2224,47 @@ module Sequel
|
|
2506
2224
|
def with_pk!(pk)
|
2507
2225
|
with_pk(pk) || raise(NoMatchingRow.new(self))
|
2508
2226
|
end
|
2227
|
+
|
2228
|
+
private
|
2229
|
+
|
2230
|
+
# If the dataset is not already ordered, and the model has a primary key,
|
2231
|
+
# return a clone ordered by the primary key.
|
2232
|
+
def _primary_key_order
|
2233
|
+
if @opts[:order].nil? && model && (pk = model.primary_key)
|
2234
|
+
cached_dataset(:_pk_order_ds){order(*pk)}
|
2235
|
+
end
|
2236
|
+
end
|
2237
|
+
|
2238
|
+
# A cached placeholder literalizer, if one exists for the current dataset.
|
2239
|
+
def _with_pk_loader
|
2240
|
+
cached_placeholder_literalizer(:_with_pk_loader) do |pl|
|
2241
|
+
table = model.table_name
|
2242
|
+
cond = case primary_key = model.primary_key
|
2243
|
+
when Array
|
2244
|
+
primary_key.map{|key| [SQL::QualifiedIdentifier.new(table, key), pl.arg]}
|
2245
|
+
when Symbol
|
2246
|
+
{SQL::QualifiedIdentifier.new(table, primary_key)=>pl.arg}
|
2247
|
+
else
|
2248
|
+
raise(Error, "#{model} does not have a primary key")
|
2249
|
+
end
|
2250
|
+
|
2251
|
+
where(cond).limit(1)
|
2252
|
+
end
|
2253
|
+
end
|
2254
|
+
|
2255
|
+
def non_sql_option?(key)
|
2256
|
+
super || key == :model
|
2257
|
+
end
|
2509
2258
|
end
|
2510
2259
|
|
2511
2260
|
extend ClassMethods
|
2512
2261
|
plugin self
|
2513
|
-
|
2262
|
+
|
2263
|
+
singleton_class.send(:undef_method, :dup, :clone, :initialize_copy)
|
2264
|
+
# :nocov:
|
2265
|
+
if RUBY_VERSION >= '1.9.3'
|
2266
|
+
# :nocov:
|
2267
|
+
singleton_class.send(:undef_method, :initialize_clone, :initialize_dup)
|
2268
|
+
end
|
2514
2269
|
end
|
2515
2270
|
end
|