sequel 4.49.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +130 -0
- data/README.rdoc +195 -136
- data/Rakefile +26 -42
- data/bin/sequel +6 -9
- data/doc/advanced_associations.rdoc +91 -168
- data/doc/association_basics.rdoc +197 -274
- data/doc/bin_sequel.rdoc +5 -3
- data/doc/cheat_sheet.rdoc +66 -43
- data/doc/code_order.rdoc +1 -8
- data/doc/core_extensions.rdoc +81 -56
- data/doc/dataset_basics.rdoc +8 -17
- data/doc/dataset_filtering.rdoc +81 -86
- data/doc/extensions.rdoc +3 -10
- data/doc/mass_assignment.rdoc +73 -30
- data/doc/migration.rdoc +19 -36
- data/doc/model_dataset_method_design.rdoc +14 -17
- data/doc/model_hooks.rdoc +15 -25
- data/doc/model_plugins.rdoc +10 -10
- data/doc/mssql_stored_procedures.rdoc +3 -3
- data/doc/object_model.rdoc +52 -70
- data/doc/opening_databases.rdoc +39 -32
- data/doc/postgresql.rdoc +48 -38
- data/doc/prepared_statements.rdoc +27 -22
- data/doc/querying.rdoc +173 -150
- 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.2.0.txt +33 -0
- data/doc/release_notes/5.3.0.txt +121 -0
- data/doc/schema_modification.rdoc +78 -64
- data/doc/security.rdoc +97 -88
- data/doc/sharding.rdoc +43 -30
- data/doc/sql.rdoc +53 -65
- data/doc/testing.rdoc +4 -5
- data/doc/thread_safety.rdoc +2 -4
- data/doc/transactions.rdoc +18 -17
- data/doc/validations.rdoc +48 -45
- data/doc/virtual_rows.rdoc +87 -115
- data/lib/sequel/adapters/ado/access.rb +7 -13
- data/lib/sequel/adapters/ado/mssql.rb +2 -9
- data/lib/sequel/adapters/ado.rb +9 -25
- data/lib/sequel/adapters/amalgalite.rb +3 -18
- data/lib/sequel/adapters/ibmdb.rb +9 -45
- data/lib/sequel/adapters/jdbc/db2.rb +8 -37
- data/lib/sequel/adapters/jdbc/derby.rb +4 -50
- data/lib/sequel/adapters/jdbc/h2.rb +6 -26
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -27
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -9
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -11
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -15
- data/lib/sequel/adapters/jdbc/oracle.rb +4 -26
- data/lib/sequel/adapters/jdbc/postgresql.rb +23 -33
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +4 -17
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -7
- data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -13
- data/lib/sequel/adapters/jdbc/transactions.rb +1 -14
- data/lib/sequel/adapters/jdbc.rb +18 -74
- data/lib/sequel/adapters/mock.rb +4 -30
- data/lib/sequel/adapters/mysql.rb +7 -44
- data/lib/sequel/adapters/mysql2.rb +5 -23
- data/lib/sequel/adapters/odbc/db2.rb +1 -1
- data/lib/sequel/adapters/odbc/mssql.rb +4 -12
- data/lib/sequel/adapters/odbc/oracle.rb +1 -1
- data/lib/sequel/adapters/odbc.rb +0 -19
- data/lib/sequel/adapters/oracle.rb +8 -13
- data/lib/sequel/adapters/postgres.rb +28 -150
- data/lib/sequel/adapters/postgresql.rb +1 -1
- data/lib/sequel/adapters/shared/access.rb +11 -51
- data/lib/sequel/adapters/shared/db2.rb +3 -61
- data/lib/sequel/adapters/shared/mssql.rb +21 -157
- data/lib/sequel/adapters/shared/mysql.rb +61 -227
- data/lib/sequel/adapters/shared/oracle.rb +13 -41
- data/lib/sequel/adapters/shared/postgres.rb +58 -264
- data/lib/sequel/adapters/shared/sqlanywhere.rb +4 -96
- data/lib/sequel/adapters/shared/sqlite.rb +22 -101
- data/lib/sequel/adapters/sqlanywhere.rb +4 -23
- data/lib/sequel/adapters/sqlite.rb +2 -19
- data/lib/sequel/adapters/tinytds.rb +5 -15
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +4 -4
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +3 -6
- data/lib/sequel/adapters/utils/replace.rb +0 -5
- data/lib/sequel/adapters/utils/stored_procedures.rb +0 -2
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +2 -0
- data/lib/sequel/ast_transformer.rb +3 -94
- data/lib/sequel/connection_pool/sharded_single.rb +1 -4
- data/lib/sequel/connection_pool/sharded_threaded.rb +97 -95
- data/lib/sequel/connection_pool/single.rb +0 -2
- data/lib/sequel/connection_pool/threaded.rb +94 -110
- data/lib/sequel/connection_pool.rb +38 -28
- data/lib/sequel/core.rb +42 -101
- data/lib/sequel/database/connecting.rb +23 -60
- data/lib/sequel/database/dataset.rb +6 -9
- data/lib/sequel/database/dataset_defaults.rb +4 -48
- data/lib/sequel/database/features.rb +5 -4
- data/lib/sequel/database/logging.rb +2 -9
- data/lib/sequel/database/misc.rb +36 -55
- data/lib/sequel/database/query.rb +8 -13
- data/lib/sequel/database/schema_generator.rb +93 -64
- data/lib/sequel/database/schema_methods.rb +61 -79
- data/lib/sequel/database/transactions.rb +4 -24
- data/lib/sequel/database.rb +12 -2
- data/lib/sequel/dataset/actions.rb +57 -107
- data/lib/sequel/dataset/dataset_module.rb +4 -16
- data/lib/sequel/dataset/features.rb +35 -30
- data/lib/sequel/dataset/graph.rb +40 -49
- data/lib/sequel/dataset/misc.rb +12 -37
- data/lib/sequel/dataset/placeholder_literalizer.rb +4 -4
- data/lib/sequel/dataset/prepared_statements.rb +23 -51
- data/lib/sequel/dataset/query.rb +91 -161
- data/lib/sequel/dataset/sql.rb +33 -225
- data/lib/sequel/dataset.rb +18 -10
- data/lib/sequel/deprecated.rb +18 -27
- data/lib/sequel/exceptions.rb +1 -17
- data/lib/sequel/extensions/_model_pg_row.rb +0 -7
- data/lib/sequel/extensions/_pretty_table.rb +1 -3
- data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
- data/lib/sequel/extensions/connection_expiration.rb +1 -1
- data/lib/sequel/extensions/connection_validator.rb +1 -1
- data/lib/sequel/extensions/constraint_validations.rb +11 -11
- data/lib/sequel/extensions/core_extensions.rb +39 -49
- data/lib/sequel/extensions/core_refinements.rb +39 -45
- data/lib/sequel/extensions/current_datetime_timestamp.rb +0 -4
- data/lib/sequel/extensions/date_arithmetic.rb +7 -7
- data/lib/sequel/extensions/duplicate_columns_handler.rb +12 -9
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
- data/lib/sequel/extensions/eval_inspect.rb +4 -11
- data/lib/sequel/extensions/freeze_datasets.rb +1 -69
- data/lib/sequel/extensions/from_block.rb +1 -35
- data/lib/sequel/extensions/graph_each.rb +2 -2
- data/lib/sequel/extensions/identifier_mangling.rb +9 -19
- data/lib/sequel/extensions/implicit_subquery.rb +2 -2
- data/lib/sequel/extensions/inflector.rb +4 -4
- data/lib/sequel/extensions/migration.rb +27 -43
- data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -84
- data/lib/sequel/extensions/null_dataset.rb +2 -8
- data/lib/sequel/extensions/pagination.rb +1 -17
- data/lib/sequel/extensions/pg_array.rb +20 -189
- data/lib/sequel/extensions/pg_extended_date_support.rb +230 -0
- data/lib/sequel/extensions/pg_hstore.rb +11 -50
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
- data/lib/sequel/extensions/pg_inet.rb +3 -16
- data/lib/sequel/extensions/pg_interval.rb +1 -20
- data/lib/sequel/extensions/pg_json.rb +7 -27
- data/lib/sequel/extensions/pg_loose_count.rb +1 -1
- data/lib/sequel/extensions/pg_range.rb +6 -121
- data/lib/sequel/extensions/pg_range_ops.rb +1 -3
- data/lib/sequel/extensions/pg_row.rb +5 -77
- data/lib/sequel/extensions/pg_row_ops.rb +2 -13
- data/lib/sequel/extensions/query.rb +3 -4
- data/lib/sequel/extensions/round_timestamps.rb +0 -6
- data/lib/sequel/extensions/schema_dumper.rb +13 -13
- data/lib/sequel/extensions/select_remove.rb +3 -3
- data/lib/sequel/extensions/split_array_nil.rb +2 -2
- data/lib/sequel/extensions/sql_comments.rb +2 -2
- data/lib/sequel/extensions/string_agg.rb +11 -8
- data/lib/sequel/extensions/symbol_aref.rb +6 -20
- data/lib/sequel/extensions/synchronize_sql.rb +45 -0
- data/lib/sequel/model/associations.rb +129 -131
- data/lib/sequel/model/base.rb +133 -731
- data/lib/sequel/model/default_inflections.rb +1 -1
- data/lib/sequel/model/errors.rb +0 -3
- data/lib/sequel/model/exceptions.rb +2 -6
- data/lib/sequel/model/inflections.rb +1 -26
- data/lib/sequel/model/plugins.rb +1 -0
- data/lib/sequel/model.rb +27 -62
- data/lib/sequel/plugins/active_model.rb +2 -5
- data/lib/sequel/plugins/association_dependencies.rb +15 -15
- data/lib/sequel/plugins/association_pks.rb +14 -28
- data/lib/sequel/plugins/association_proxies.rb +6 -7
- data/lib/sequel/plugins/auto_validations.rb +4 -4
- data/lib/sequel/plugins/before_after_save.rb +0 -43
- data/lib/sequel/plugins/blacklist_security.rb +9 -8
- data/lib/sequel/plugins/boolean_readers.rb +3 -3
- data/lib/sequel/plugins/boolean_subsets.rb +2 -2
- data/lib/sequel/plugins/caching.rb +5 -5
- data/lib/sequel/plugins/class_table_inheritance.rb +71 -102
- data/lib/sequel/plugins/column_conflicts.rb +2 -2
- data/lib/sequel/plugins/column_select.rb +2 -2
- data/lib/sequel/plugins/composition.rb +15 -24
- data/lib/sequel/plugins/constraint_validations.rb +4 -3
- data/lib/sequel/plugins/csv_serializer.rb +13 -20
- data/lib/sequel/plugins/dataset_associations.rb +2 -2
- data/lib/sequel/plugins/def_dataset_method.rb +5 -5
- data/lib/sequel/plugins/defaults_setter.rb +1 -1
- data/lib/sequel/plugins/delay_add_association.rb +1 -1
- data/lib/sequel/plugins/finder.rb +16 -10
- data/lib/sequel/plugins/force_encoding.rb +1 -7
- data/lib/sequel/plugins/hook_class_methods.rb +4 -106
- data/lib/sequel/plugins/input_transformer.rb +10 -11
- data/lib/sequel/plugins/insert_returning_select.rb +1 -9
- data/lib/sequel/plugins/instance_filters.rb +5 -5
- data/lib/sequel/plugins/instance_hooks.rb +7 -52
- data/lib/sequel/plugins/inverted_subsets.rb +3 -1
- data/lib/sequel/plugins/json_serializer.rb +19 -19
- data/lib/sequel/plugins/lazy_attributes.rb +1 -10
- data/lib/sequel/plugins/list.rb +6 -6
- data/lib/sequel/plugins/many_through_many.rb +11 -8
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +3 -3
- data/lib/sequel/plugins/nested_attributes.rb +18 -31
- data/lib/sequel/plugins/optimistic_locking.rb +3 -3
- data/lib/sequel/plugins/pg_array_associations.rb +8 -2
- data/lib/sequel/plugins/pg_row.rb +2 -11
- data/lib/sequel/plugins/prepared_statements.rb +13 -66
- data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +7 -7
- data/lib/sequel/plugins/serialization.rb +15 -33
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +2 -8
- data/lib/sequel/plugins/single_table_inheritance.rb +10 -13
- data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
- data/lib/sequel/plugins/static_cache.rb +8 -9
- data/lib/sequel/plugins/string_stripper.rb +3 -3
- data/lib/sequel/plugins/subclasses.rb +1 -1
- data/lib/sequel/plugins/subset_conditions.rb +2 -2
- data/lib/sequel/plugins/table_select.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
- data/lib/sequel/plugins/timestamps.rb +6 -7
- data/lib/sequel/plugins/touch.rb +4 -8
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/typecast_on_load.rb +2 -2
- data/lib/sequel/plugins/unlimited_update.rb +1 -7
- data/lib/sequel/plugins/update_or_create.rb +3 -3
- data/lib/sequel/plugins/update_refresh.rb +3 -3
- data/lib/sequel/plugins/uuid.rb +7 -11
- data/lib/sequel/plugins/validation_class_methods.rb +10 -9
- data/lib/sequel/plugins/validation_contexts.rb +4 -4
- data/lib/sequel/plugins/validation_helpers.rb +26 -25
- data/lib/sequel/plugins/whitelist_security.rb +13 -9
- data/lib/sequel/plugins/xml_serializer.rb +24 -25
- data/lib/sequel/sql.rb +145 -276
- data/lib/sequel/timezones.rb +8 -23
- data/lib/sequel/version.rb +2 -2
- data/lib/sequel.rb +1 -1
- data/spec/adapter_spec.rb +1 -1
- data/spec/adapters/db2_spec.rb +2 -103
- data/spec/adapters/mssql_spec.rb +89 -68
- data/spec/adapters/mysql_spec.rb +111 -478
- data/spec/adapters/oracle_spec.rb +1 -9
- data/spec/adapters/postgres_spec.rb +459 -664
- data/spec/adapters/spec_helper.rb +12 -31
- data/spec/adapters/sqlanywhere_spec.rb +2 -77
- data/spec/adapters/sqlite_spec.rb +8 -146
- data/spec/bin_spec.rb +11 -16
- data/spec/core/connection_pool_spec.rb +173 -74
- data/spec/core/database_spec.rb +96 -244
- data/spec/core/dataset_spec.rb +99 -414
- data/spec/core/deprecated_spec.rb +3 -3
- data/spec/core/expression_filters_spec.rb +37 -144
- data/spec/core/mock_adapter_spec.rb +241 -4
- data/spec/core/object_graph_spec.rb +11 -60
- data/spec/core/placeholder_literalizer_spec.rb +1 -14
- data/spec/core/schema_generator_spec.rb +51 -40
- data/spec/core/schema_spec.rb +88 -77
- data/spec/core/spec_helper.rb +6 -24
- data/spec/core/version_spec.rb +1 -1
- data/spec/core_extensions_spec.rb +7 -83
- data/spec/core_model_spec.rb +2 -2
- data/spec/deprecation_helper.rb +2 -14
- data/spec/extensions/accessed_columns_spec.rb +1 -1
- data/spec/extensions/active_model_spec.rb +3 -3
- data/spec/extensions/after_initialize_spec.rb +1 -1
- data/spec/extensions/arbitrary_servers_spec.rb +2 -2
- data/spec/extensions/association_dependencies_spec.rb +1 -1
- data/spec/extensions/association_pks_spec.rb +30 -92
- data/spec/extensions/association_proxies_spec.rb +1 -1
- data/spec/extensions/auto_literal_strings_spec.rb +1 -12
- data/spec/extensions/auto_validations_spec.rb +1 -1
- data/spec/extensions/blacklist_security_spec.rb +1 -1
- data/spec/extensions/blank_spec.rb +1 -1
- data/spec/extensions/boolean_readers_spec.rb +1 -1
- data/spec/extensions/boolean_subsets_spec.rb +1 -1
- data/spec/extensions/caching_spec.rb +1 -1
- data/spec/extensions/class_table_inheritance_spec.rb +53 -1118
- data/spec/extensions/column_conflicts_spec.rb +1 -1
- data/spec/extensions/column_select_spec.rb +4 -4
- data/spec/extensions/columns_introspection_spec.rb +1 -1
- data/spec/extensions/columns_updated_spec.rb +1 -1
- data/spec/extensions/composition_spec.rb +8 -30
- data/spec/extensions/connection_expiration_spec.rb +3 -3
- data/spec/extensions/connection_validator_spec.rb +3 -3
- data/spec/extensions/constraint_validations_plugin_spec.rb +1 -1
- data/spec/extensions/constraint_validations_spec.rb +1 -1
- data/spec/extensions/core_refinements_spec.rb +1 -3
- data/spec/extensions/csv_serializer_spec.rb +4 -9
- data/spec/extensions/current_datetime_timestamp_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +2 -1
- data/spec/extensions/dataset_source_alias_spec.rb +1 -1
- data/spec/extensions/date_arithmetic_spec.rb +3 -3
- data/spec/extensions/def_dataset_method_spec.rb +1 -1
- data/spec/extensions/defaults_setter_spec.rb +2 -2
- data/spec/extensions/delay_add_association_spec.rb +8 -9
- data/spec/extensions/dirty_spec.rb +1 -1
- data/spec/extensions/duplicate_columns_handler_spec.rb +1 -1
- data/spec/extensions/eager_each_spec.rb +2 -2
- data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
- data/spec/extensions/error_splitter_spec.rb +1 -1
- data/spec/extensions/error_sql_spec.rb +1 -1
- data/spec/extensions/eval_inspect_spec.rb +1 -1
- data/spec/extensions/finder_spec.rb +1 -1
- data/spec/extensions/force_encoding_spec.rb +2 -5
- data/spec/extensions/freeze_datasets_spec.rb +1 -1
- data/spec/extensions/graph_each_spec.rb +5 -5
- data/spec/extensions/hook_class_methods_spec.rb +1 -194
- data/spec/extensions/identifier_mangling_spec.rb +17 -170
- data/spec/extensions/implicit_subquery_spec.rb +1 -5
- data/spec/extensions/inflector_spec.rb +1 -1
- data/spec/extensions/input_transformer_spec.rb +7 -2
- data/spec/extensions/insert_returning_select_spec.rb +1 -1
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/instance_hooks_spec.rb +1 -95
- data/spec/extensions/inverted_subsets_spec.rb +1 -1
- data/spec/extensions/json_serializer_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +1 -7
- data/spec/extensions/list_spec.rb +5 -6
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +25 -33
- data/spec/extensions/migration_spec.rb +12 -2
- data/spec/extensions/modification_detection_spec.rb +1 -1
- data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
- data/spec/extensions/named_timezones_spec.rb +3 -3
- data/spec/extensions/nested_attributes_spec.rb +1 -29
- data/spec/extensions/null_dataset_spec.rb +1 -11
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pagination_spec.rb +1 -1
- data/spec/extensions/pg_array_associations_spec.rb +22 -26
- data/spec/extensions/pg_array_ops_spec.rb +1 -1
- data/spec/extensions/pg_array_spec.rb +3 -48
- data/spec/extensions/pg_enum_spec.rb +1 -1
- data/spec/extensions/pg_extended_date_support_spec.rb +122 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +1 -1
- data/spec/extensions/pg_hstore_spec.rb +22 -31
- data/spec/extensions/pg_inet_ops_spec.rb +1 -1
- data/spec/extensions/pg_inet_spec.rb +1 -14
- data/spec/extensions/pg_interval_spec.rb +3 -13
- data/spec/extensions/pg_json_ops_spec.rb +1 -1
- data/spec/extensions/pg_json_spec.rb +1 -13
- data/spec/extensions/pg_loose_count_spec.rb +1 -1
- data/spec/extensions/pg_range_ops_spec.rb +1 -1
- data/spec/extensions/pg_range_spec.rb +3 -88
- data/spec/extensions/pg_row_ops_spec.rb +1 -1
- data/spec/extensions/pg_row_plugin_spec.rb +1 -1
- data/spec/extensions/pg_row_spec.rb +1 -44
- data/spec/extensions/pg_static_cache_updater_spec.rb +1 -1
- data/spec/extensions/prepared_statements_safe_spec.rb +7 -7
- data/spec/extensions/prepared_statements_spec.rb +13 -48
- data/spec/extensions/pretty_table_spec.rb +40 -9
- data/spec/extensions/query_spec.rb +1 -12
- data/spec/extensions/rcte_tree_spec.rb +23 -34
- data/spec/extensions/round_timestamps_spec.rb +1 -5
- data/spec/extensions/s_spec.rb +1 -1
- data/spec/extensions/schema_caching_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +43 -32
- data/spec/extensions/select_remove_spec.rb +1 -1
- data/spec/extensions/sequel_4_dataset_methods_spec.rb +1 -1
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +5 -17
- data/spec/extensions/server_block_spec.rb +1 -1
- data/spec/extensions/server_logging_spec.rb +2 -2
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/extensions/shared_caching_spec.rb +1 -28
- data/spec/extensions/single_table_inheritance_spec.rb +2 -5
- data/spec/extensions/singular_table_names_spec.rb +1 -1
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +5 -27
- data/spec/extensions/split_array_nil_spec.rb +1 -1
- data/spec/extensions/split_values_spec.rb +1 -1
- data/spec/extensions/sql_comments_spec.rb +1 -1
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/static_cache_spec.rb +1 -1
- data/spec/extensions/string_agg_spec.rb +2 -2
- data/spec/extensions/string_date_time_spec.rb +1 -1
- data/spec/extensions/string_stripper_spec.rb +1 -1
- data/spec/extensions/subclasses_spec.rb +1 -1
- data/spec/extensions/subset_conditions_spec.rb +1 -1
- data/spec/extensions/symbol_aref_refinement_spec.rb +1 -1
- data/spec/extensions/symbol_as_refinement_spec.rb +1 -1
- data/spec/extensions/synchronize_sql_spec.rb +124 -0
- data/spec/extensions/table_select_spec.rb +4 -4
- data/spec/extensions/tactical_eager_loading_spec.rb +1 -6
- data/spec/extensions/thread_local_timezones_spec.rb +1 -1
- data/spec/extensions/timestamps_spec.rb +5 -7
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/tree_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +1 -1
- data/spec/extensions/update_or_create_spec.rb +12 -16
- data/spec/extensions/update_primary_key_spec.rb +4 -3
- data/spec/extensions/update_refresh_spec.rb +1 -1
- data/spec/extensions/uuid_spec.rb +10 -13
- data/spec/extensions/validate_associated_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +3 -3
- data/spec/extensions/validation_contexts_spec.rb +1 -1
- data/spec/extensions/validation_helpers_spec.rb +10 -44
- data/spec/extensions/whitelist_security_spec.rb +5 -5
- data/spec/extensions/xml_serializer_spec.rb +8 -13
- data/spec/guards_helper.rb +2 -1
- data/spec/integration/associations_test.rb +1 -23
- data/spec/integration/database_test.rb +7 -7
- data/spec/integration/dataset_test.rb +12 -47
- data/spec/integration/eager_loader_test.rb +1 -1
- data/spec/integration/migrator_test.rb +1 -1
- data/spec/integration/model_test.rb +4 -82
- data/spec/integration/plugin_test.rb +7 -23
- data/spec/integration/prepared_statement_test.rb +8 -88
- data/spec/integration/schema_test.rb +10 -10
- data/spec/integration/spec_helper.rb +17 -21
- data/spec/integration/timezone_test.rb +5 -5
- data/spec/integration/transaction_test.rb +3 -55
- data/spec/integration/type_test.rb +9 -9
- data/spec/model/association_reflection_spec.rb +24 -9
- data/spec/model/associations_spec.rb +124 -303
- data/spec/model/base_spec.rb +43 -137
- data/spec/model/class_dataset_methods_spec.rb +2 -20
- data/spec/model/dataset_methods_spec.rb +1 -20
- data/spec/model/eager_loading_spec.rb +48 -17
- data/spec/model/hooks_spec.rb +5 -300
- data/spec/model/inflector_spec.rb +1 -1
- data/spec/model/model_spec.rb +29 -339
- data/spec/model/plugins_spec.rb +2 -16
- data/spec/model/record_spec.rb +33 -129
- data/spec/model/spec_helper.rb +5 -15
- data/spec/model/validations_spec.rb +1 -1
- data/spec/sequel_warning.rb +1 -12
- metadata +19 -65
- data/doc/active_record.rdoc +0 -927
- data/lib/sequel/adapters/cubrid.rb +0 -160
- data/lib/sequel/adapters/do/mysql.rb +0 -69
- data/lib/sequel/adapters/do/postgres.rb +0 -46
- data/lib/sequel/adapters/do/sqlite3.rb +0 -41
- data/lib/sequel/adapters/do.rb +0 -166
- data/lib/sequel/adapters/jdbc/as400.rb +0 -92
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -65
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -37
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -34
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -34
- data/lib/sequel/adapters/odbc/progress.rb +0 -12
- data/lib/sequel/adapters/shared/cubrid.rb +0 -245
- data/lib/sequel/adapters/shared/firebird.rb +0 -261
- data/lib/sequel/adapters/shared/informix.rb +0 -63
- data/lib/sequel/adapters/shared/progress.rb +0 -40
- data/lib/sequel/adapters/swift/mysql.rb +0 -50
- data/lib/sequel/adapters/swift/postgres.rb +0 -49
- data/lib/sequel/adapters/swift/sqlite.rb +0 -48
- data/lib/sequel/adapters/swift.rb +0 -169
- data/lib/sequel/adapters/utils/pg_types.rb +0 -4
- data/lib/sequel/dataset/mutation.rb +0 -98
- data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +0 -117
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -8
- data/lib/sequel/extensions/filter_having.rb +0 -65
- data/lib/sequel/extensions/hash_aliases.rb +0 -51
- data/lib/sequel/extensions/meta_def.rb +0 -37
- data/lib/sequel/extensions/query_literals.rb +0 -86
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -26
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -133
- data/lib/sequel/extensions/set_overrides.rb +0 -82
- data/lib/sequel/no_core_ext.rb +0 -4
- data/lib/sequel/plugins/association_autoreloading.rb +0 -11
- data/lib/sequel/plugins/identifier_columns.rb +0 -49
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -11
- data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -90
- data/lib/sequel/plugins/prepared_statements_associations.rb +0 -137
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -71
- data/lib/sequel/plugins/schema.rb +0 -84
- data/lib/sequel/plugins/scissors.rb +0 -37
- data/spec/core/dataset_mutation_spec.rb +0 -253
- data/spec/extensions/_deprecated_identifier_mangling_spec.rb +0 -314
- data/spec/extensions/before_after_save_spec.rb +0 -40
- data/spec/extensions/filter_having_spec.rb +0 -42
- data/spec/extensions/from_block_spec.rb +0 -21
- data/spec/extensions/hash_aliases_spec.rb +0 -26
- data/spec/extensions/identifier_columns_spec.rb +0 -19
- data/spec/extensions/meta_def_spec.rb +0 -35
- data/spec/extensions/no_auto_literal_strings_spec.rb +0 -69
- data/spec/extensions/pg_typecast_on_load_spec.rb +0 -70
- data/spec/extensions/prepared_statements_associations_spec.rb +0 -212
- data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -40
- data/spec/extensions/query_literals_spec.rb +0 -185
- data/spec/extensions/schema_spec.rb +0 -123
- data/spec/extensions/scissors_spec.rb +0 -27
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -118
- data/spec/extensions/set_overrides_spec.rb +0 -75
data/doc/dataset_basics.rdoc
CHANGED
@@ -2,16 +2,7 @@
|
|
2
2
|
|
3
3
|
== Introduction
|
4
4
|
|
5
|
-
Datasets are the primary way Sequel uses to access the database. While most database libraries have specific support for updating all records or only a single record, Sequel's ability to represent SQL queries themselves as
|
6
|
-
|
7
|
-
== What a Dataset Represents
|
8
|
-
|
9
|
-
A Dataset can be thought of representing one of two concepts:
|
10
|
-
|
11
|
-
* An SQL query
|
12
|
-
* An abstract set of rows and some related behavior
|
13
|
-
|
14
|
-
The first concept is more easily understood, so you should probably start with that assumption.
|
5
|
+
Datasets are the primary way Sequel uses to access the database. While most database libraries have specific support for updating all records or only a single record, Sequel's ability to represent SQL queries themselves as datasets is what gives Sequel most of its power. This document aims to give a basic introduction to datasets and how to use them.
|
15
6
|
|
16
7
|
== Basics
|
17
8
|
|
@@ -22,9 +13,9 @@ The most basic dataset is the simple selection of all columns in a table:
|
|
22
13
|
|
23
14
|
Here, DB represents your Sequel::Database object, and ds is your dataset, with the SQL query it represents below it.
|
24
15
|
|
25
|
-
One of the core dataset ideas that should be understood is that datasets use a functional style of modification, in which methods called on the dataset return modified copies of the dataset, they don't modify the dataset themselves:
|
16
|
+
One of the core dataset ideas that should be understood is that datasets are frozen and use a functional style of modification, in which methods called on the dataset return modified copies of the dataset, they don't modify the dataset themselves:
|
26
17
|
|
27
|
-
ds2 = ds.where(:
|
18
|
+
ds2 = ds.where(id: 1)
|
28
19
|
ds2
|
29
20
|
# SELECT * FROM posts WHERE id = 1
|
30
21
|
ds
|
@@ -35,7 +26,7 @@ Note how ds itself is not modified. This is because ds.where returns a modified
|
|
35
26
|
# Thread safe:
|
36
27
|
100.times do |i|
|
37
28
|
Thread.new do
|
38
|
-
ds.where(:
|
29
|
+
ds.where(id: i).first
|
39
30
|
end
|
40
31
|
end
|
41
32
|
|
@@ -77,7 +68,7 @@ Most dataset methods fall into this category, which can be further broken down b
|
|
77
68
|
SELECT:: select, select_all, select_append, select_group, select_more
|
78
69
|
FROM:: from, from_self
|
79
70
|
JOIN:: join, left_join, right_join, full_join, natural_join, natural_left_join, natural_right_join, natural_full_join, cross_join, inner_join, left_outer_join, right_outer_join, full_outer_join, join_table
|
80
|
-
WHERE:: where, filter, exclude,
|
71
|
+
WHERE:: where, filter, exclude, or, grep, invert, unfiltered
|
81
72
|
GROUP:: group, group_by, group_and_count, group_append, select_group, ungrouped
|
82
73
|
HAVING:: having, exclude_having, invert, unfiltered
|
83
74
|
ORDER:: order, order_by, order_append, order_prepend, order_more, reverse, reverse_order, unordered
|
@@ -85,16 +76,16 @@ LIMIT/OFFSET:: limit, offset, unlimited
|
|
85
76
|
compounds:: union, intersect, except
|
86
77
|
locking:: for_update, lock_style
|
87
78
|
common table expressions:: with, with_recursive
|
88
|
-
other::
|
79
|
+
other:: distinct, naked, qualify, server, with_sql
|
89
80
|
|
90
81
|
=== Methods that execute code on the database
|
91
82
|
|
92
83
|
Most other dataset methods commonly used will execute the dataset's SQL on the database:
|
93
84
|
|
94
|
-
SELECT (All Records):: all, each, map,
|
85
|
+
SELECT (All Records):: all, each, map, as_hash, to_hash_groups, select_map, select_order_map, select_hash, select_hash_groups
|
95
86
|
SELECT (First Record):: first, last, [], single_record
|
96
87
|
SELECT (Single Value):: get, single_value
|
97
|
-
SELECT (Aggregates):: count, avg, max, min, sum
|
88
|
+
SELECT (Aggregates):: count, avg, max, min, sum
|
98
89
|
INSERT:: insert, <<, import, multi_insert
|
99
90
|
UPDATE:: update
|
100
91
|
DELETE:: delete
|
data/doc/dataset_filtering.rdoc
CHANGED
@@ -1,206 +1,201 @@
|
|
1
1
|
= Dataset Filtering
|
2
2
|
|
3
|
-
Sequel is very flexible when it comes to filtering records. You can specify your conditions as a
|
4
|
-
|
5
|
-
== Filtering using a custom filter string
|
6
|
-
|
7
|
-
If you wish to write your SQL by hand, you can just supply it to the dataset's #where method:
|
8
|
-
|
9
|
-
items.where('x < 10').sql
|
10
|
-
#=> "SELECT * FROM items WHERE x < 10"
|
11
|
-
|
12
|
-
In order to prevent SQL injection, you can replace literal values with question marks and supply the values as additional arguments:
|
13
|
-
|
14
|
-
items.where('category = ?', 'ruby').sql
|
15
|
-
#=> "SELECT * FROM items WHERE category = 'ruby'"
|
16
|
-
|
17
|
-
You can also use placeholders with :placeholder and a hash of placeholder values:
|
18
|
-
|
19
|
-
items.where('category = :category', :category=>'ruby').sql
|
20
|
-
#=> "SELECT * FROM items WHERE category = 'ruby'"
|
21
|
-
|
22
|
-
=== Specifying SQL functions
|
23
|
-
|
24
|
-
Sequel also allows you to specify functions by using the Sequel.function method:
|
25
|
-
|
26
|
-
items.literal(Sequel.function(:avg, :price)) #=> "avg(price)"
|
27
|
-
|
28
|
-
If you are specifying a filter/selection/order, you can use a virtual row block:
|
29
|
-
|
30
|
-
items.select{avg(price)}
|
31
|
-
|
32
|
-
You can also use the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc] and the +sql_function+ method:
|
33
|
-
|
34
|
-
:avg.sql_function(:price)
|
3
|
+
Sequel is very flexible when it comes to filtering records. You can specify your conditions as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions, or as an SQL code fragment (with optional parameters), .
|
35
4
|
|
36
5
|
== Filtering using a hash
|
37
6
|
|
38
7
|
If you just need to compare records against values, you can supply a hash:
|
39
8
|
|
40
|
-
items.where(:
|
41
|
-
|
9
|
+
items.where(category: 'ruby').sql
|
10
|
+
# "SELECT * FROM items WHERE (category = 'ruby')"
|
42
11
|
|
43
12
|
Sequel can check for null values:
|
44
13
|
|
45
|
-
items.where(:
|
46
|
-
|
14
|
+
items.where(category: nil).sql
|
15
|
+
# "SELECT * FROM items WHERE (category IS NULL)"
|
47
16
|
|
48
17
|
Or compare two columns:
|
49
18
|
|
50
|
-
items.where{{:
|
51
|
-
|
19
|
+
items.where{{x: some_table[:y]}}.sql
|
20
|
+
# "SELECT * FROM items WHERE (x = some_table.y)"
|
52
21
|
|
53
22
|
And also compare against multiple values:
|
54
23
|
|
55
|
-
items.where(:
|
56
|
-
|
24
|
+
items.where(category: ['ruby', 'perl']).sql
|
25
|
+
# "SELECT * FROM items WHERE (category IN ('ruby', 'perl'))"
|
57
26
|
|
58
27
|
Ranges (both inclusive and exclusive) can also be used:
|
59
28
|
|
60
|
-
items.where(:
|
61
|
-
|
29
|
+
items.where(price: 100..200).sql
|
30
|
+
# "SELECT * FROM items WHERE (price >= 100 AND price <= 200)"
|
62
31
|
|
63
|
-
items.where(:
|
64
|
-
|
32
|
+
items.where(price: 100...200).sql
|
33
|
+
# "SELECT * FROM items WHERE (price >= 100 AND price < 200)"
|
65
34
|
|
66
35
|
== Filtering using an array
|
67
36
|
|
68
37
|
If you need to select multiple items from a dataset, you can supply an array:
|
69
38
|
|
70
|
-
|
71
|
-
items
|
72
|
-
#=> "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
|
39
|
+
items.where(id: [1, 38, 47, 99]).sql
|
40
|
+
# "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
|
73
41
|
|
74
42
|
== Filtering using expressions
|
75
43
|
|
76
|
-
You can pass a block to where, which is evaluated in a special context:
|
44
|
+
You can pass a block to where (referred to as a virtual row block), which is evaluated in a special context:
|
77
45
|
|
78
46
|
items.where{price * 2 < 50}.sql
|
79
|
-
|
47
|
+
# "SELECT * FROM items WHERE ((price * 2) < 50)
|
80
48
|
|
81
49
|
This works for the standard inequality and arithmetic operators:
|
82
50
|
|
83
51
|
items.where{price + 100 < 200}.sql
|
84
|
-
|
52
|
+
# "SELECT * FROM items WHERE ((price + 100) < 200)
|
85
53
|
|
86
54
|
items.where{price - 100 > 200}.sql
|
87
|
-
|
55
|
+
# "SELECT * FROM items WHERE ((price - 100) > 200)
|
88
56
|
|
89
57
|
items.where{price * 100 <= 200}.sql
|
90
|
-
|
58
|
+
# "SELECT * FROM items WHERE ((price * 100) <= 200)
|
91
59
|
|
92
60
|
items.where{price / 100 >= 200}.sql
|
93
|
-
|
61
|
+
# "SELECT * FROM items WHERE ((price / 100) >= 200)
|
94
62
|
|
95
63
|
items.where{price ** 2 >= 200}.sql
|
96
|
-
|
64
|
+
# "SELECT * FROM items WHERE (power(price, 2) >= 200)
|
97
65
|
|
98
66
|
You use the overloaded bitwise and (&) and or (|) operators to combine expressions:
|
99
67
|
|
100
68
|
items.where{(price + 100 < 200) & (price * 100 <= 200)}.sql
|
101
|
-
|
69
|
+
# "SELECT * FROM items WHERE (((price + 100) < 200) AND ((price * 100) <= 200))
|
102
70
|
|
103
71
|
items.where{(price - 100 > 200) | (price / 100 >= 200)}.sql
|
104
|
-
|
72
|
+
# "SELECT * FROM items WHERE (((price - 100) > 200) OR ((price / 100) >= 200))
|
105
73
|
|
106
74
|
To filter by equality, you use the standard hash, which can be combined with other expressions using Sequel.& and Sequel.|:
|
107
75
|
|
108
|
-
items.where{Sequel.&({:
|
109
|
-
|
76
|
+
items.where{Sequel.&({category: 'ruby'}, (price + 100 < 200))}.sql
|
77
|
+
# "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
|
110
78
|
|
111
79
|
You can also use the =~ operator:
|
112
80
|
|
113
81
|
items.where{(category =~ 'ruby') & (price + 100 < 200)}.sql
|
114
|
-
|
82
|
+
# "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
|
115
83
|
|
116
84
|
This works with other hash values, such as arrays and ranges:
|
117
85
|
|
118
|
-
items.where{Sequel.|({:
|
119
|
-
|
86
|
+
items.where{Sequel.|({category: ['ruby', 'other']}, (price - 100 > 200))}.sql
|
87
|
+
# "SELECT * FROM items WHERE ((category IN ('ruby', 'other')) OR ((price - 100) <= 200))"
|
120
88
|
|
121
89
|
items.where{(price =~ (100..200)) & :active}.sql
|
122
|
-
|
90
|
+
# "SELECT * FROM items WHERE ((price >= 100 AND price <= 200) AND active)"
|
91
|
+
|
92
|
+
== Filtering using a custom filter string
|
93
|
+
|
94
|
+
If you wish to include an SQL fragment as part of a filter, you need to wrap it with +Sequel.lit+ to mark that it is literal SQL code, and pass it to the #where method:
|
95
|
+
|
96
|
+
items.where(Sequel.lit('x < 10')).sql
|
97
|
+
# "SELECT * FROM items WHERE x < 10"
|
98
|
+
|
99
|
+
In order to prevent SQL injection, you can replace literal values with question marks and supply the values as additional arguments to +Sequel.lit+:
|
100
|
+
|
101
|
+
items.where(Sequel.lit('category = ?', 'ruby')).sql
|
102
|
+
# "SELECT * FROM items WHERE category = 'ruby'"
|
103
|
+
|
104
|
+
You can also use placeholders with :placeholder and a hash of placeholder values:
|
105
|
+
|
106
|
+
items.where(Sequel.lit('category = :category', category: "ruby")).sql
|
107
|
+
# "SELECT * FROM items WHERE category = 'ruby'"
|
108
|
+
|
109
|
+
=== Specifying SQL functions
|
110
|
+
|
111
|
+
Sequel also allows you to specify functions by using the Sequel.function method:
|
112
|
+
|
113
|
+
items.literal(Sequel.function(:avg, :price)) # "avg(price)"
|
114
|
+
|
115
|
+
If you are specifying a filter/selection/order, you can use a virtual row block:
|
116
|
+
|
117
|
+
items.select{avg(price)}
|
123
118
|
|
124
119
|
=== Negating conditions
|
125
120
|
|
126
121
|
You can use the exclude method to exclude whole conditions:
|
127
122
|
|
128
|
-
items.exclude(:
|
129
|
-
|
123
|
+
items.exclude(category: 'ruby').sql
|
124
|
+
# "SELECT * FROM items WHERE (category != 'ruby')"
|
130
125
|
|
131
126
|
items.exclude(:active).sql
|
132
|
-
|
127
|
+
# "SELECT * FROM items WHERE NOT active"
|
133
128
|
|
134
129
|
items.exclude{price / 100 >= 200}.sql
|
135
|
-
|
130
|
+
# "SELECT * FROM items WHERE ((price / 100) < 200)
|
136
131
|
|
137
132
|
To exclude only parts of conditions, you can use when in combination with Sequel.~ or the ~ method on Sequel expressions:
|
138
133
|
|
139
|
-
items.where{Sequel.&(Sequel.~(:
|
140
|
-
|
134
|
+
items.where{Sequel.&(Sequel.~(category: 'ruby'), (price + 100 < 200))}.sql
|
135
|
+
# "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
|
141
136
|
|
142
137
|
items.where{~(category =~ 'ruby') & (price + 100 < 200)}.sql
|
143
|
-
|
138
|
+
# "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
|
144
139
|
|
145
|
-
|
140
|
+
You can also use the !~ method:
|
146
141
|
|
147
142
|
items.where{(category !~ 'ruby') & (price + 100 < 200)}.sql
|
148
|
-
|
143
|
+
# "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
|
149
144
|
|
150
145
|
=== Comparing against column references
|
151
146
|
|
152
147
|
You can also compare against other columns:
|
153
148
|
|
154
149
|
items.where{credit > debit}.sql
|
155
|
-
|
150
|
+
# "SELECT * FROM items WHERE (credit > debit)
|
156
151
|
|
157
152
|
Or against SQL functions:
|
158
153
|
|
159
154
|
items.where{price - 100 < max(price)}.sql
|
160
|
-
|
155
|
+
# "SELECT * FROM items WHERE ((price - 100) < max(price))"
|
161
156
|
|
162
157
|
== String search functions
|
163
158
|
|
164
159
|
You can search SQL strings in a case sensitive manner using the Sequel.like method:
|
165
160
|
|
166
161
|
items.where(Sequel.like(:name, 'Acme%')).sql
|
167
|
-
|
162
|
+
# "SELECT * FROM items WHERE (name LIKE 'Acme%' ESCAPE '\')"
|
168
163
|
|
169
164
|
You can search SQL strings in a case insensitive manner using the Sequel.ilike method:
|
170
165
|
|
171
166
|
items.where(Sequel.ilike(:name, 'Acme%')).sql
|
172
|
-
|
167
|
+
# "SELECT * FROM items WHERE (name ILIKE 'Acme%' ESCAPE '\')"
|
173
168
|
|
174
|
-
You can specify a Regexp as a like argument, but this will probably only work
|
169
|
+
You can specify a Regexp as a hash value (or like argument), but this will probably only work
|
175
170
|
on PostgreSQL and MySQL:
|
176
171
|
|
177
|
-
items.where(
|
178
|
-
|
172
|
+
items.where(name: /Acme.*/).sql
|
173
|
+
# "SELECT * FROM items WHERE (name ~ 'Acme.*')"
|
179
174
|
|
180
175
|
Like can also take more than one argument:
|
181
176
|
|
182
177
|
items.where(Sequel.like(:name, 'Acme%', /Beta.*/)).sql
|
183
|
-
|
178
|
+
# "SELECT * FROM items WHERE ((name LIKE 'Acme%' ESCAPE '\') OR (name ~ 'Beta.*'))"
|
184
179
|
|
185
180
|
== String concatenation
|
186
181
|
|
187
182
|
You can concatenate SQL strings using Sequel.join:
|
188
183
|
|
189
184
|
items.where(Sequel.join([:name, :comment]).like('Jo%nice%')).sql
|
190
|
-
|
185
|
+
# "SELECT * FROM items WHERE ((name || comment) LIKE 'Jo%nice%' ESCAPE '\')"
|
191
186
|
|
192
187
|
Sequel.join also takes a join argument:
|
193
188
|
|
194
189
|
items.where(Sequel.join([:name, :comment], ':').like('John:%nice%')).sql
|
195
|
-
|
190
|
+
# "SELECT * FROM items WHERE ((name || ':' || comment) LIKE 'John:%nice%' ESCAPE '\')"
|
196
191
|
|
197
192
|
== Filtering using sub-queries
|
198
193
|
|
199
|
-
|
194
|
+
Datasets can be used as subqueries. Subqueries can be very useful for filtering records, and many times provide a simpler alternative to table joins. Subqueries can be used in all forms of filters:
|
200
195
|
|
201
196
|
refs = consumer_refs.where(:logged_in).select(:consumer_id)
|
202
|
-
consumers.where(:
|
203
|
-
|
197
|
+
consumers.where(id: refs).sql
|
198
|
+
# "SELECT * FROM consumers WHERE (id IN (SELECT consumer_id FROM consumer_refs WHERE logged_in))"
|
204
199
|
|
205
200
|
Note that if you are checking for the inclusion of a single column in a subselect, the subselect should only select a single column.
|
206
201
|
|
@@ -208,5 +203,5 @@ Note that if you are checking for the inclusion of a single column in a subselec
|
|
208
203
|
|
209
204
|
By default, if you chain calls to +where+, the conditions get ANDed together. If you want to use an OR for a condition, you can use the +or+ method:
|
210
205
|
|
211
|
-
items.where(:
|
212
|
-
|
206
|
+
items.where(name: 'Food').or(vendor: 1).sql
|
207
|
+
# "SELECT * FROM items WHERE ((name = 'Food') OR (vendor = 1))"
|
data/doc/extensions.rdoc
CHANGED
@@ -10,7 +10,7 @@ Global extensions are loaded via <tt>Sequel.extension</tt>:
|
|
10
10
|
|
11
11
|
Sequel.extension :named_timezones
|
12
12
|
|
13
|
-
|
13
|
+
All this does is require the relevent extension from <tt>sequel/extensions/named_timezones</tt> somewhere in the ruby path. Global extensions are just a simpler, consistent way to require code that modifies Sequel.
|
14
14
|
|
15
15
|
== Database Extensions
|
16
16
|
|
@@ -28,18 +28,11 @@ All future <tt>Sequel::Database</tt> instances created afterward will then autom
|
|
28
28
|
|
29
29
|
== Dataset Extensions
|
30
30
|
|
31
|
-
Dataset extensions should add or modify the behavior of a single <tt>Sequel::Dataset</tt> instance. They are loaded via <tt>Sequel::Dataset#extension</tt
|
31
|
+
Dataset extensions should add or modify the behavior of a single <tt>Sequel::Dataset</tt> instance. They are loaded via <tt>Sequel::Dataset#extension</tt>. <tt>Sequel::Dataset#extension</tt> returns a modifies copy of the dataset that includes the extension (similar to how most dataset query methods work):
|
32
32
|
|
33
33
|
ds = DB[:a].extension(:columns_introspection)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
ds = DB[:a]
|
38
|
-
ds.extension!(:columns_introspection)
|
39
|
-
|
40
|
-
It is recommended you only use <tt>Sequel::Dataset#extension!</tt> if you have good reasons to.
|
41
|
-
|
42
|
-
The first thing loading a Dataset extension does is load the relevent extension globally. Similar to Database extensions, loading a Dataset extension globally should not affect state other than maybe adding a module. After loading the extension globally, it modifies the related <tt>Sequel::Dataset</tt> instance to modify its behavior.
|
35
|
+
The first thing loading a Dataset extension does is load the relevent extension globally. Similar to Database extensions, loading a Dataset extension globally should not affect state other than maybe adding a module. After loading the extension globally, it returned a modified copy of the <tt>Sequel::Dataset</tt> with the extension loaded into it.
|
43
36
|
|
44
37
|
If you want to load an extension into all future datasets for a given <tt>Sequel::Database</tt> instance, you can also load it as a Database extension:
|
45
38
|
|
data/doc/mass_assignment.rdoc
CHANGED
@@ -1,33 +1,42 @@
|
|
1
1
|
= Sequel::Model Mass Assignment
|
2
2
|
|
3
|
-
Most Model methods that take a hash of attribute keys and values, including <tt>Model.new</tt>,
|
4
|
-
|
3
|
+
Most Model methods that take a hash of attribute keys and values, including <tt>Model.new</tt>,
|
4
|
+
<tt>Model.create</tt>, <tt>Model#set</tt> and <tt>Model#update</tt> are subject to Sequel's mass assignment rules.
|
5
|
+
|
6
|
+
If you have an instance of a plain Sequel::Model class:
|
7
|
+
|
8
|
+
class Post < Sequel::Model
|
9
|
+
end
|
10
|
+
post = Post.new
|
11
|
+
|
12
|
+
and you call a mass assignment method with a hash:
|
13
|
+
|
14
|
+
post.set(title: 'T', body: 'B')
|
15
|
+
|
16
|
+
the mass assignment method will go through each key in the hash, append <tt>=</tt> to it to determine the
|
17
|
+
setter method, and if the setter method is defined and access to it is not restricted, Sequel will call the
|
18
|
+
setter method with the hash value. So if we assume that the posts table has subject and text columns, what
|
19
|
+
the above mass assignment call actually does is:
|
20
|
+
|
21
|
+
post.title=('T')
|
22
|
+
post.body=('B')
|
23
|
+
|
5
24
|
By default, there are two types of setter methods that are restricted.
|
6
25
|
The first is methods like <tt>typecast_on_assignment=</tt> and <tt>==</tt>, which don't affect columns.
|
7
26
|
These methods cannot be enabled for mass assignment.
|
8
27
|
The second is primary key setters.
|
9
|
-
To enable use of primary key setters, you need to call +unrestrict_primary_key+ for that model:
|
10
28
|
|
11
|
-
|
12
|
-
|
13
|
-
Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
|
14
|
-
Sequel has multiple ways of securing mass assignment.
|
15
|
-
The first way is using +set_allowed_columns+:
|
29
|
+
So if you do:
|
16
30
|
|
17
|
-
Post.
|
31
|
+
post = Post.new(id: 1)
|
18
32
|
|
19
|
-
|
20
|
-
This method is useful in simple applications where the same columns are allowed in all cases, but not appropriate when different columns are allowed in different scenarios (e.g. admin access vs. user access).
|
21
|
-
To handle cases where different columns are allowed in different cases, you can use +set_only+ or +update_only+:
|
33
|
+
Sequel will raise a Sequel::MassAssignmentRestriction exception, since by default setting the primary key is not allowed.
|
22
34
|
|
23
|
-
|
24
|
-
post.set_only(params[:post], :title, :body)
|
25
|
-
# admin case
|
26
|
-
post.set_only(params[:post], :title, :body, :deleted)
|
35
|
+
To enable use of primary key setters, you need to call +unrestrict_primary_key+ for that model:
|
27
36
|
|
28
|
-
|
37
|
+
Post.unrestrict_primary_key
|
29
38
|
|
30
|
-
|
39
|
+
If you want to change mass assignment so it ignores attempts to access restricted setter methods, you can do:
|
31
40
|
|
32
41
|
# Global default
|
33
42
|
Sequel::Model.strict_param_setting = false
|
@@ -36,20 +45,54 @@ By default, if an invalid setter method call is attempted, Sequel raises a <tt>S
|
|
36
45
|
# Instance level
|
37
46
|
post.strict_param_setting = false
|
38
47
|
|
39
|
-
|
40
|
-
|
48
|
+
Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
|
49
|
+
If you are dealing with untrusted input, you are generally going to want to restrict what should be updated.
|
50
|
+
|
51
|
+
Sequel has <tt>Model#set_fields</tt> and <tt>Model#update_fields</tt> methods, which are designed to be used with untrused input.
|
52
|
+
These methods take two arguments, the untrusted hash as the first argument, and a trusted array of field names as the second argument:
|
41
53
|
|
42
|
-
post.set_fields(
|
54
|
+
post.set_fields({title: 'T', body: 'B'}, [:title, :body])
|
43
55
|
|
44
|
-
+set_fields+
|
45
|
-
|
46
|
-
|
56
|
+
Instead of looking at every key in the untrusted hash, +set_fields+ will iterate over the trusted field names, looking each up in the hash, and
|
57
|
+
calling the setter method appropriately with the result. +set_fields+ basically translates the above method call to:
|
58
|
+
|
59
|
+
post.title=('T')
|
60
|
+
post.body=('B')
|
61
|
+
|
62
|
+
By using this method, you can be sure that the mass assignment method only sets the fields you expect it to set.
|
63
|
+
|
64
|
+
Note that if one of the fields does not exist in the hash:
|
65
|
+
|
66
|
+
post.set_fields({title: 'T'}, [:title, :body])
|
67
|
+
|
68
|
+
+set_fields+ will set the value to nil (the default hash value) by default, with behavior equivalent to:
|
69
|
+
|
70
|
+
post.title=('T')
|
71
|
+
post.body=(nil)
|
72
|
+
|
73
|
+
You can use the :missing option to +set_fields+ to change the behavior:
|
74
|
+
|
75
|
+
post.set_fields({title: 'T'}, [:title, :body], missing: :skip)
|
76
|
+
# post.title=('T') # only
|
77
|
+
|
78
|
+
post.set_fields({title: 'T'}, [:title, :body], missing: :raise)
|
79
|
+
# raises Sequel::Error
|
80
|
+
|
81
|
+
If you want to set a model level default for the +set_fields+ options, you can use the +default_set_fields_options+ class accessor:
|
82
|
+
|
83
|
+
# Global default
|
84
|
+
Sequel::Model.default_set_fields_options[:missing] = :skip
|
85
|
+
# Class level
|
86
|
+
Post.default_set_fields_options[:missing] = :skip
|
47
87
|
|
48
|
-
|
49
|
-
They work great for things like HTML forms where the form fields are static.
|
50
|
-
+set_only+ and +update_only+ are designed for cases where you are not sure what fields are going to be present in the input, but still want to make sure only certain setter methods can be called.
|
51
|
-
They work great for flexible APIs.
|
88
|
+
Here's a table describing Sequel's default mass assignment methods:
|
52
89
|
|
53
|
-
|
90
|
+
Model.new(hash) :: Creates a new model instance, then calls Model#set(hash)
|
91
|
+
Model.create(hash) :: Calls Model.new(hash).save
|
92
|
+
Model#set(hash) :: Calls related setter method (unless access is restricted) for each key in the hash, then returns self
|
93
|
+
Model#update(hash) :: Calls set(hash).save_changes
|
94
|
+
Model#set_fields(hash, columns, options) :: For each column in columns, looks up related entry in hash, and calls the related setter method
|
95
|
+
Model#update_fields(hash, columns, options) :: Calls set_fields(hash, columns, options).save_changes
|
54
96
|
|
55
|
-
|
97
|
+
For backwards compatibility, Sequel also ships with a whitelist_security and blacklist_security plugins that offer additional mass assignment
|
98
|
+
methods, but it is recommended to use +set_fields+ or +update_fields+ for untrusted input, and the other methods for trusted input.
|