sequel 4.49.0 → 5.0.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 +4 -4
- data/CHANGELOG +70 -0
- data/README.rdoc +195 -136
- data/Rakefile +26 -42
- data/bin/sequel +3 -5
- data/doc/advanced_associations.rdoc +86 -163
- 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/schema_modification.rdoc +63 -60
- data/doc/security.rdoc +97 -88
- data/doc/sharding.rdoc +43 -30
- data/doc/sql.rdoc +53 -65
- data/doc/testing.rdoc +3 -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.rb +1 -1
- data/lib/sequel/adapters/ado.rb +9 -25
- data/lib/sequel/adapters/ado/access.rb +7 -13
- data/lib/sequel/adapters/ado/mssql.rb +2 -9
- data/lib/sequel/adapters/amalgalite.rb +3 -18
- data/lib/sequel/adapters/ibmdb.rb +9 -45
- data/lib/sequel/adapters/jdbc.rb +13 -73
- 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 +4 -25
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -26
- 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 +1 -15
- data/lib/sequel/adapters/jdbc/oracle.rb +4 -26
- data/lib/sequel/adapters/jdbc/postgresql.rb +2 -31
- 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/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.rb +0 -19
- 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/oracle.rb +7 -13
- data/lib/sequel/adapters/postgres.rb +13 -57
- 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 +23 -224
- data/lib/sequel/adapters/shared/oracle.rb +13 -41
- data/lib/sequel/adapters/shared/postgres.rb +44 -259
- data/lib/sequel/adapters/shared/sqlanywhere.rb +4 -96
- data/lib/sequel/adapters/shared/sqlite.rb +12 -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 +2 -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.rb +26 -28
- 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/core.rb +42 -101
- data/lib/sequel/database.rb +12 -2
- 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 +23 -55
- data/lib/sequel/database/query.rb +8 -13
- data/lib/sequel/database/schema_generator.rb +89 -64
- data/lib/sequel/database/schema_methods.rb +61 -79
- data/lib/sequel/database/transactions.rb +4 -24
- data/lib/sequel/dataset.rb +18 -10
- data/lib/sequel/dataset/actions.rb +53 -107
- data/lib/sequel/dataset/dataset_module.rb +3 -15
- data/lib/sequel/dataset/features.rb +30 -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 +71 -155
- data/lib/sequel/dataset/sql.rb +30 -225
- 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 +23 -40
- 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_hstore.rb +11 -50
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
- data/lib/sequel/extensions/pg_inet.rb +2 -15
- 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/model.rb +27 -62
- data/lib/sequel/model/associations.rb +128 -131
- data/lib/sequel/model/base.rb +171 -711
- 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/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 -22
- data/lib/sequel/version.rb +2 -2
- 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 +101 -480
- data/spec/adapters/oracle_spec.rb +1 -9
- data/spec/adapters/postgres_spec.rb +312 -565
- 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 +64 -244
- data/spec/core/dataset_spec.rb +81 -415
- data/spec/core/deprecated_spec.rb +3 -3
- data/spec/core/expression_filters_spec.rb +37 -144
- data/spec/core/mock_adapter_spec.rb +176 -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 +74 -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 +4 -59
- 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 +35 -1086
- 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 +1 -7
- 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 +1 -1
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +1 -1
- data/spec/extensions/migration_spec.rb +2 -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 +1 -1
- data/spec/extensions/pagination_spec.rb +1 -1
- data/spec/extensions/pg_array_associations_spec.rb +4 -1
- 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_hstore_ops_spec.rb +1 -1
- data/spec/extensions/pg_hstore_spec.rb +23 -32
- 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 +1 -1
- data/spec/extensions/prepared_statements_spec.rb +13 -48
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +1 -12
- data/spec/extensions/rcte_tree_spec.rb +1 -1
- 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 +1 -1
- 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 +2 -14
- 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/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 +3 -3
- 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 +1 -1
- 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 -12
- 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 +3 -3
- 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 +5 -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 +6 -22
- data/spec/integration/prepared_statement_test.rb +8 -88
- data/spec/integration/schema_test.rb +6 -6
- data/spec/integration/spec_helper.rb +13 -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 +18 -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 +17 -11
- data/spec/model/hooks_spec.rb +5 -300
- data/spec/model/inflector_spec.rb +1 -1
- data/spec/model/model_spec.rb +15 -320
- data/spec/model/plugins_spec.rb +2 -16
- data/spec/model/record_spec.rb +29 -121
- data/spec/model/spec_helper.rb +5 -15
- data/spec/model/validations_spec.rb +1 -1
- data/spec/sequel_warning.rb +1 -12
- metadata +8 -64
- data/doc/active_record.rdoc +0 -927
- data/lib/sequel/adapters/cubrid.rb +0 -160
- data/lib/sequel/adapters/do.rb +0 -166
- 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/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.rb +0 -169
- 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/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/security.rdoc
CHANGED
@@ -16,14 +16,11 @@ as it never calls eval on a string that is derived from user input.
|
|
16
16
|
However, some Sequel methods used for creating methods via metaprogramming
|
17
17
|
could conceivably be abused to do so:
|
18
18
|
|
19
|
-
* Sequel::Schema::CreateTableGenerator.add_type_method
|
20
|
-
* Sequel::Dataset.def_mutation_method
|
21
19
|
* Sequel::Dataset.def_sql_method
|
22
|
-
* Sequel::
|
23
|
-
* Sequel.def_adapter_method (private)
|
24
|
-
* Sequel::SQL::Expression.to_s_method (private)
|
25
|
-
* Sequel::Plugins::HookClassMethods::ClassMethods#add_hook_type
|
20
|
+
* Sequel::JDBC.load_driver
|
26
21
|
* Sequel::Plugins.def_dataset_methods
|
22
|
+
* Sequel::Dataset.prepared_statements_module (private)
|
23
|
+
* Sequel::SQL::Expression.to_s_method (private)
|
27
24
|
|
28
25
|
As long as you don't call those with user input, you should not be
|
29
26
|
vulnerable to code execution.
|
@@ -48,6 +45,9 @@ There are basically two kinds of possible SQL injections in Sequel:
|
|
48
45
|
Some Sequel methods are designed to execute raw SQL strings, including:
|
49
46
|
|
50
47
|
* Sequel::Database#execute
|
48
|
+
* Sequel::Database#execute_ddl
|
49
|
+
* Sequel::Database#execute_dui
|
50
|
+
* Sequel::Database#execute_insert
|
51
51
|
* Sequel::Database#run
|
52
52
|
* Sequel::Database#<<
|
53
53
|
* Sequel::Dataset#fetch_rows
|
@@ -61,9 +61,12 @@ Some Sequel methods are designed to execute raw SQL strings, including:
|
|
61
61
|
|
62
62
|
Here are some examples of use:
|
63
63
|
|
64
|
+
DB.execute 'SQL'
|
65
|
+
DB.execute_ddl 'SQL'
|
66
|
+
DB.execute_dui 'SQL'
|
67
|
+
DB.execute_insert 'SQL'
|
64
68
|
DB.run 'SQL'
|
65
69
|
DB << 'SQL'
|
66
|
-
DB.execute 'SQL'
|
67
70
|
DB.fetch_rows('SQL'){|row| }
|
68
71
|
DB.dataset.with_sql_all('SQL')
|
69
72
|
DB.dataset.with_sql_delete('SQL')
|
@@ -102,19 +105,16 @@ With these methods you should use placeholders, in which case Sequel automatical
|
|
102
105
|
|
103
106
|
Sequel generally treats ruby strings as SQL strings (escaping them correctly), and
|
104
107
|
not as raw SQL. However, you can convert a ruby string to a literal string, and
|
105
|
-
Sequel will then treat it as raw SQL. This is typically done through
|
106
|
-
|
107
|
-
or Sequel.lit[rdoc-ref:Sequel::SQL::Builders#lit] if they are not in use.
|
108
|
+
Sequel will then treat it as raw SQL. This is typically done through
|
109
|
+
Sequel.lit[rdoc-ref:Sequel::SQL::Builders#lit].
|
108
110
|
|
109
|
-
'a'.lit
|
110
111
|
Sequel.lit('a')
|
111
112
|
|
112
|
-
Using
|
113
|
+
Using Sequel.lit[rdoc-ref:Sequel::SQL::Builders#lit] to turn a ruby string into a literal string results
|
113
114
|
in SQL injection if the string is derived from user input. With both of these
|
114
115
|
methods, the strings can contain placeholders, which you can use to safely include
|
115
116
|
user input inside a literal string:
|
116
117
|
|
117
|
-
'a = ?'.lit(params[:user_id].to_s)
|
118
118
|
Sequel.lit('a = ?', params[:user_id].to_s)
|
119
119
|
|
120
120
|
Even though they have similar names, note that Sequel::Database#literal operates very differently from
|
@@ -132,91 +132,107 @@ a ruby string as raw SQL. For example:
|
|
132
132
|
|
133
133
|
==== SQL Filter Fragments
|
134
134
|
|
135
|
-
|
135
|
+
Starting in Sequel 5, Sequel does not automatically convert plain strings to
|
136
|
+
literal strings in typical code. Instead, you can use Sequel.lit to
|
137
|
+
create literal strings:
|
136
138
|
|
137
|
-
|
139
|
+
Sequel.lit("name > 'A'")
|
138
140
|
|
139
|
-
|
140
|
-
|
141
|
+
To safely include user input as part of an SQL filter fragment, use Sequel.lit
|
142
|
+
with placeholders:
|
141
143
|
|
142
|
-
DB[:table].where("name >
|
144
|
+
DB[:table].where(Sequel.lit("name > ?", params[:id].to_s)) # Safe
|
143
145
|
|
144
|
-
|
146
|
+
Be careful to never call Sequel.lit where the first argument is derived from
|
147
|
+
user input.
|
145
148
|
|
146
|
-
|
147
|
-
|
148
|
-
Note that for that type of query, Sequel generally encourages the following form:
|
149
|
+
There are a few uncommon cases where Sequel will still convert
|
150
|
+
plain strings to literal strings.
|
149
151
|
|
150
|
-
|
152
|
+
==== SQL Fragment passed to Dataset#lock_style and Model#lock!
|
151
153
|
|
152
|
-
Sequel
|
153
|
-
code
|
154
|
+
The Sequel::Dataset#lock_style and Sequel::Model#lock! methods also treat
|
155
|
+
an input string as SQL code. This method should not be called with user input.
|
154
156
|
|
155
|
-
|
156
|
-
|
157
|
-
|
157
|
+
DB[:table].lock_style(params[:id]) # SQL injection!
|
158
|
+
Album.first.lock!(params[:id]) # SQL injection!
|
159
|
+
|
160
|
+
==== SQL Type Names
|
161
|
+
|
162
|
+
In general, most places where Sequel needs to use an SQL type that should
|
163
|
+
be specified by the user, it allows you to use a ruby string, and that
|
164
|
+
string is used verbatim as the SQL type. You should not use user input
|
165
|
+
for type strings.
|
166
|
+
|
167
|
+
DB[:table].select(Sequel.cast(:a, params[:id])) # SQL injection!
|
168
|
+
|
169
|
+
==== SQL Function Names
|
170
|
+
|
171
|
+
In most cases, Sequel does not quote SQL function names. You should not use
|
172
|
+
user input for function names.
|
173
|
+
|
174
|
+
DB[:table].select(Sequel.function(params[:id])) # SQL injection!
|
175
|
+
|
176
|
+
==== auto_literal_strings extension
|
177
|
+
|
178
|
+
If the auto_literal_strings extension is used for backwards compatibility,
|
179
|
+
then Sequel will treat plain strings as literal strings if they are used
|
180
|
+
as the first argument to a filtering method. This can lead to SQL
|
181
|
+
injection:
|
182
|
+
|
183
|
+
DB[:table].where("name > #{params[:id].to_s}")
|
184
|
+
# SQL injection when using auto_literal_strings extension
|
185
|
+
|
186
|
+
If you are using the auto_literal_strings extension, you need to be very careful,
|
187
|
+
as the following methods will treat a plain string given as the first arguments
|
188
|
+
as a literal strings:
|
158
189
|
|
159
190
|
* Sequel::Dataset#where
|
160
191
|
* Sequel::Dataset#having
|
161
192
|
* Sequel::Dataset#filter
|
162
193
|
* Sequel::Dataset#exclude
|
163
|
-
* Sequel::Dataset#exclude_where
|
164
194
|
* Sequel::Dataset#exclude_having
|
165
|
-
* Sequel::Dataset#and
|
166
195
|
* Sequel::Dataset#or
|
167
196
|
* Sequel::Dataset#first
|
168
197
|
* Sequel::Dataset#last
|
169
198
|
* Sequel::Dataset#[]
|
170
199
|
|
171
|
-
|
172
|
-
class methods also call down to the filter methods.
|
200
|
+
Even stuff that looks like it may be safe isn't:
|
173
201
|
|
174
|
-
|
175
|
-
|
202
|
+
DB[:table].first(params[:num_rows])
|
203
|
+
# SQL injection when using auto_literal_strings extension
|
176
204
|
|
177
|
-
|
205
|
+
The Model.find[rdoc-ref:Sequel::Model::ClassMethods#find] and
|
206
|
+
Model.find_or_create[rdoc-ref:Sequel::Model::ClassMethods#find_or_create]
|
207
|
+
class methods also will treat string arguments as literal strings if the
|
208
|
+
auto_literal_strings extension is used:
|
178
209
|
|
179
|
-
|
180
|
-
|
210
|
+
Album.find(params[:id])
|
211
|
+
# SQL injection when using auto_literal_strings extension
|
212
|
+
|
213
|
+
Similar to the filter methods, the auto_literal_strings extension
|
214
|
+
also makes Sequel::Dataset#update treats a string argument as raw SQL:
|
181
215
|
|
182
216
|
DB[:table].update("column = 1")
|
183
217
|
|
184
218
|
So you should not do:
|
185
219
|
|
186
|
-
DB[:table].update(
|
220
|
+
DB[:table].update(params[:changes])
|
221
|
+
# SQL injection when using auto_literal_strings extension
|
187
222
|
|
188
|
-
|
223
|
+
or:
|
189
224
|
|
190
|
-
DB[:table].update(
|
225
|
+
DB[:table].update("column = #{params[:value].to_s}")
|
226
|
+
# SQL injection when using auto_literal_strings extension
|
191
227
|
|
192
|
-
|
193
|
-
for plain strings as literal strings in update methods.
|
194
|
-
|
195
|
-
==== SQL Fragment passed to Dataset#lock_style and Model#lock!
|
196
|
-
|
197
|
-
The Sequel::Dataset#lock_style and Sequel::Model#lock! methods also treat
|
198
|
-
an input string as SQL code. This method should not be called with user input.
|
199
|
-
|
200
|
-
==== SQL Fragment passed to Virtual Row #` method
|
201
|
-
|
202
|
-
Virtual row blocks currently support a #` method for using literal SQL:
|
203
|
-
|
204
|
-
DB[:table].where{a > `some SQL`}
|
205
|
-
|
206
|
-
This method should not be called with user input.
|
207
|
-
|
208
|
-
==== SQL Type Names
|
209
|
-
|
210
|
-
In general, most places where Sequel needs to use an SQL type that should
|
211
|
-
be specified by the user, it allows you to use a ruby string, and that
|
212
|
-
string is used verbatim as the SQL type. You should not use user input
|
213
|
-
for type strings.
|
214
|
-
|
215
|
-
==== SQL Function Names
|
228
|
+
Instead, you should do:
|
216
229
|
|
217
|
-
|
218
|
-
user input for function names.
|
230
|
+
DB[:table].update(:column => params[:value].to_s) # Safe
|
219
231
|
|
232
|
+
Because using the auto_literal_strings extension makes SQL injection
|
233
|
+
so much eaiser, it is recommended to not use it, and instead
|
234
|
+
use Sequel.lit with placeholders.
|
235
|
+
|
220
236
|
=== SQL Identifier Injections
|
221
237
|
|
222
238
|
Usually, Sequel treats ruby symbols as SQL identifiers, and ruby
|
@@ -236,7 +252,7 @@ the Sequel::Dataset#insert and Sequel::Dataset#update methods:
|
|
236
252
|
DB[:t].insert('b'=>1) # INSERT INTO "t" ("b") VALUES (1)
|
237
253
|
|
238
254
|
Note how the identifier is still quoted in these cases. Sequel quotes identifiers by default
|
239
|
-
on most databases. However, it does not quote identifiers by default on DB2
|
255
|
+
on most databases. However, it does not quote identifiers by default on DB2.
|
240
256
|
On those databases using an identifier derived from user input can lead to SQL injection.
|
241
257
|
Similarly, if you turn off identifier quoting manually on other databases, you open yourself
|
242
258
|
up to SQL injection if you use identifiers derived from user input.
|
@@ -262,6 +278,10 @@ uses symbols as identifiers. However, if you are creating symbols from user inp
|
|
262
278
|
you at least have a denial of service vulnerability in ruby <2.2, and possibly a
|
263
279
|
more serious vulnerability.
|
264
280
|
|
281
|
+
Note that many Database schema modification methods (e.g. create_table, add_column)
|
282
|
+
also allow for SQL identifier injections, and possibly also SQL code injections.
|
283
|
+
These methods should never be called with user input.
|
284
|
+
|
265
285
|
== Denial of Service
|
266
286
|
|
267
287
|
Sequel converts some strings to symbols. Because symbols in ruby <2.2 are not
|
@@ -293,7 +313,7 @@ if you allow the user to control the alias name:
|
|
293
313
|
|
294
314
|
DB[:table].select(:column.as(params[:alias]))
|
295
315
|
|
296
|
-
Then you have a denial of service vulnerability. In general, such a vulnerability
|
316
|
+
Then you can have a denial of service vulnerability. In general, such a vulnerability
|
297
317
|
is unlikely, because you are probably indexing into the returned hash(es) by name,
|
298
318
|
and if an alias was used and you didn't expect it, your application wouldn't work.
|
299
319
|
|
@@ -353,28 +373,17 @@ These two methods iterate over the second argument (+:name+ and +:copies_sold+ i
|
|
353
373
|
this example) instead of iterating over the entries in the first argument
|
354
374
|
(<tt>params[:album]</tt> in this example).
|
355
375
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
which are similar but iterate over the entries in the first argument, checking
|
360
|
-
the second argument to see if setting the entries is allowed.
|
361
|
-
|
362
|
-
album.set_only(params[:album], [:name, :copies_sold])
|
363
|
-
album.update_only(params[:album], [:name, :copies_sold])
|
364
|
-
|
365
|
-
If you expect all entries in the second argument to be present in the first
|
366
|
-
argument, use +set_fields+ or +update_fields+. If you are not sure if all
|
367
|
-
arguments in the second argument will be present in the first argument, but
|
368
|
-
do not want to allow setting any column other than the ones listed in the
|
369
|
-
second argument, use +set_only+ or +update_only+.
|
370
|
-
|
371
|
-
You can override the columns to allow by default during mass assignment via
|
372
|
-
the Model.set_allowed_columns[rdoc-ref:Sequel::Model::ClassMethods#set_allowed_columns] class method. This is a good
|
373
|
-
practice, though being explicit on a per-call basis is still recommended:
|
376
|
+
If you want to override the columns that Model#set[rdoc-ref:Sequel::Model::InstanceMethods#set]
|
377
|
+
allows by default during mass assignment, you can use the whitelist_security plugin, then call
|
378
|
+
the set_allowed_columns class method.
|
374
379
|
|
380
|
+
Album.plugin :whitelist_security
|
375
381
|
Album.set_allowed_columns(:name, :copies_sold)
|
376
382
|
Album.create(params[:album]) # Only name and copies_sold set
|
377
383
|
|
384
|
+
Being explicit on a per-call basis using the set_fields and update_fields methods is recommended
|
385
|
+
instead of using the whitelist_security plugin and setting a global whitelist.
|
386
|
+
|
378
387
|
For more details on the mass assignment methods, see the {Mass Assignment Guide}[rdoc-ref:doc/mass_assignment.rdoc].
|
379
388
|
|
380
389
|
== General Parameter Handling
|
@@ -386,7 +395,7 @@ their type. For example:
|
|
386
395
|
Album.where(:id=>params[:id])
|
387
396
|
|
388
397
|
is probably a bad idea. Assuming you are using a web framework, <tt>params[:id]</tt> could
|
389
|
-
be a string, an array, a hash, or
|
398
|
+
be a string, an array, a hash, nil, or potentially something else.
|
390
399
|
|
391
400
|
Assuming that +id+ is an integer field, you probably want to do:
|
392
401
|
|
@@ -400,7 +409,7 @@ a string:
|
|
400
409
|
If you are trying to use an IN clause with a list of id values based on input provided
|
401
410
|
on a web form:
|
402
411
|
|
403
|
-
Album.where(:id=>params[:ids].to_a.map
|
412
|
+
Album.where(:id=>params[:ids].to_a.map(&:to_i))
|
404
413
|
|
405
414
|
Basically, be as explicit as possible. While there aren't any known security issues
|
406
415
|
in Sequel when you do:
|
data/doc/sharding.rdoc
CHANGED
@@ -13,7 +13,7 @@ option. Using the :servers database option makes Sequel use a connection pool
|
|
13
13
|
class that supports sharding, and the minimum required to enable sharding
|
14
14
|
support is to use the empty hash:
|
15
15
|
|
16
|
-
DB=Sequel.connect('postgres://master_server/database', :
|
16
|
+
DB=Sequel.connect('postgres://master_server/database', servers: {})
|
17
17
|
|
18
18
|
In most cases, you are probably not going to want to use an empty hash. Keys in the server hash are
|
19
19
|
not restricted to type, but the general recommendation is to use a symbol
|
@@ -35,8 +35,8 @@ tables you are accessing, unless you really know what you are doing.
|
|
35
35
|
To use a single, read-only slave that handles SELECT queries, the following
|
36
36
|
is the simplest configuration:
|
37
37
|
|
38
|
-
DB=Sequel.connect('postgres://master_server/database',
|
39
|
-
:
|
38
|
+
DB=Sequel.connect('postgres://master_server/database',
|
39
|
+
servers: {read_only: {host: 'slave_server'}})
|
40
40
|
|
41
41
|
This will use the slave_server for SELECT queries and master_server for
|
42
42
|
other queries.
|
@@ -48,8 +48,8 @@ the symbol name defined in the connect options. For example:
|
|
48
48
|
# Force the SELECT to run on the master
|
49
49
|
DB[:users].server(:default).all
|
50
50
|
|
51
|
-
# Force the
|
52
|
-
DB[:users].server(:read_only).
|
51
|
+
# Force the DELETE to run on the read-only slave
|
52
|
+
DB[:users].server(:read_only).delete
|
53
53
|
|
54
54
|
=== Multiple Read-Only Slaves, Single Master
|
55
55
|
|
@@ -59,13 +59,13 @@ slave_server1, slave_server2, and slave_server3.
|
|
59
59
|
num_read_only = 4
|
60
60
|
read_only_host = rand(num_read_only)
|
61
61
|
read_only_proc = proc do |db|
|
62
|
-
{:
|
62
|
+
{host: "slave_server#{(read_only_host+=1) % num_read_only}"}
|
63
63
|
end
|
64
|
-
DB=Sequel.connect('postgres://master_server/database',
|
65
|
-
:
|
64
|
+
DB=Sequel.connect('postgres://master_server/database',
|
65
|
+
servers: {read_only: read_only_proc})
|
66
66
|
|
67
67
|
This will use one of the slave servers for SELECT queries and use the
|
68
|
-
|
68
|
+
master server for other queries. It's also possible to pick a random host
|
69
69
|
instead of using the round robin approach presented above, but that can result
|
70
70
|
in less optimal resource usage.
|
71
71
|
|
@@ -78,15 +78,15 @@ it shows that the master database is named :default. So for 4 masters and
|
|
78
78
|
num_read_only = 4
|
79
79
|
read_only_host = rand(num_read_only)
|
80
80
|
read_only_proc = proc do |db|
|
81
|
-
{:
|
81
|
+
{host: "slave_server#{(read_only_host+=1) % num_read_only}"}
|
82
82
|
end
|
83
83
|
num_default = 4
|
84
84
|
default_host = rand(num_default)
|
85
85
|
default_proc = proc do |db|
|
86
|
-
{:
|
86
|
+
{host: "master_server#{(default_host+=1) % num_default}"}
|
87
87
|
end
|
88
|
-
DB=Sequel.connect('postgres://master_server/database',
|
89
|
-
:
|
88
|
+
DB=Sequel.connect('postgres://master_server/database',
|
89
|
+
servers: {default: default_proc, read_only: read_only_proc})
|
90
90
|
|
91
91
|
== Sharding
|
92
92
|
|
@@ -100,16 +100,16 @@ of 16 shards). First, you need to configure the database:
|
|
100
100
|
|
101
101
|
servers = {}
|
102
102
|
(('0'..'9').to_a + ('a'..'f').to_a).each do |hex|
|
103
|
-
servers[hex.to_sym] = {:
|
103
|
+
servers[hex.to_sym] = {host: "hash_host_#{hex}"}
|
104
104
|
end
|
105
|
-
DB=Sequel.connect('postgres://hash_host/hashes', :servers
|
105
|
+
DB=Sequel.connect('postgres://hash_host/hashes', servers: servers)
|
106
106
|
|
107
107
|
This configures 17 servers, the 16 shard servers (/hash_host_[0-9a-f]/), and 1
|
108
108
|
default server which will be used if no shard is specified ("hash_host"). If
|
109
109
|
you want the default server to be one of the shard servers (e.g. hash_host_a),
|
110
110
|
it's easiest to do:
|
111
111
|
|
112
|
-
DB=Sequel.connect('postgres://hash_host_a/hashes', :servers
|
112
|
+
DB=Sequel.connect('postgres://hash_host_a/hashes', servers: servers)
|
113
113
|
|
114
114
|
That will still set up a second pool of connections for the default server,
|
115
115
|
since it considers the default server and shard servers independent. Note that
|
@@ -120,7 +120,7 @@ schemas, so you should always have a default server that works.
|
|
120
120
|
|
121
121
|
To set the shard for a given query, you use the Dataset#server method:
|
122
122
|
|
123
|
-
DB[:hashes].server(:a).where(:
|
123
|
+
DB[:hashes].server(:a).where(hash: /31337/)
|
124
124
|
|
125
125
|
That will return all matching rows on the hash_host_a shard that have a hash
|
126
126
|
column that contains 31337.
|
@@ -133,7 +133,7 @@ the shard to use. This is fairly easy using a Sequel::Model:
|
|
133
133
|
dataset_module do
|
134
134
|
def plaintext_for_hash(hash)
|
135
135
|
raise(ArgumentError, 'Invalid SHA-1 Hash') unless /\A[0-9a-f]{40}\z/.match(hash)
|
136
|
-
server(hash[0...1].to_sym).where(:hash
|
136
|
+
server(hash[0...1].to_sym).where(hash: hash).get(:plaintext)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
@@ -146,24 +146,24 @@ to assume the :default shard. However, you can specify a
|
|
146
146
|
different shard using the :servers_hash option when connecting
|
147
147
|
to the database:
|
148
148
|
|
149
|
-
DB = Sequel.connect('postgres://...', :
|
149
|
+
DB = Sequel.connect('postgres://...', servers_hash: Hash.new(:some_shard))
|
150
150
|
|
151
151
|
You can also use this feature to raise an exception if an
|
152
152
|
unconfigured shard is used:
|
153
153
|
|
154
|
-
DB = Sequel.connect('postgres://...', :
|
154
|
+
DB = Sequel.connect('postgres://...', servers_hash: Hash.new{raise 'foo'})
|
155
155
|
|
156
156
|
If you specify a :servers_hash option to raise an exception for non configured
|
157
157
|
shards you should also explicitly specify a :read_only entry in your :servers option
|
158
158
|
for the case where a shard is not specified. In most cases it is sufficient
|
159
159
|
to make the :read_only entry the same as the :default shard:
|
160
160
|
|
161
|
-
servers = {:
|
161
|
+
servers = {read_only: {}}
|
162
162
|
(('0'..'9').to_a + ('a'..'f').to_a).each do |hex|
|
163
|
-
servers[hex.to_sym] = {:
|
163
|
+
servers[hex.to_sym] = {host: "hash_host_#{hex}"}
|
164
164
|
end
|
165
|
-
DB=Sequel.connect('postgres://hash_host/hashes', :servers
|
166
|
-
:
|
165
|
+
DB=Sequel.connect('postgres://hash_host/hashes', servers: servers,
|
166
|
+
servers_hash: Hash.new{raise "Invalid Server"})
|
167
167
|
|
168
168
|
=== Sharding Plugin
|
169
169
|
|
@@ -176,7 +176,7 @@ work well with shards. You just need to remember to set to model to use the plu
|
|
176
176
|
plugin :sharding
|
177
177
|
end
|
178
178
|
|
179
|
-
Rainbow.server(:a).first(:
|
179
|
+
Rainbow.server(:a).first(id: 1).update(plaintext: 'VGM')
|
180
180
|
|
181
181
|
If all of your models are sharded, you can set all models to use the plugin via:
|
182
182
|
|
@@ -186,7 +186,7 @@ If all of your models are sharded, you can set all models to use the plugin via:
|
|
186
186
|
|
187
187
|
By default, you must specify the server/shard you want to use for every dataset/action,
|
188
188
|
or Sequel will use the default shard. If you have a group of queries that should use the
|
189
|
-
same shard, it can get a bit
|
189
|
+
same shard, it can get a bit redundant to specify the same shard for all of them.
|
190
190
|
|
191
191
|
The server_block extension adds a Database#with_server method that scopes all database
|
192
192
|
access inside the block to the given shard by default:
|
@@ -194,7 +194,7 @@ access inside the block to the given shard by default:
|
|
194
194
|
DB.extension :server_block
|
195
195
|
DB.with_server(:a) do
|
196
196
|
# this SELECT query uses the "a" shard
|
197
|
-
if r = Rainbow.first(:
|
197
|
+
if r = Rainbow.first(hash: /31337/)
|
198
198
|
r.count += 1
|
199
199
|
# this UPDATE query also uses the "a" shard
|
200
200
|
r.save
|
@@ -209,6 +209,19 @@ you retrieve the models inside the block and save them outside of the block. If
|
|
209
209
|
need to do that, call the server method explicitly on the dataset used to retrieve the
|
210
210
|
model objects.
|
211
211
|
|
212
|
+
The with_server method also supports a second argument for the default read_only server
|
213
|
+
to use, which can be useful if you are mixing sharding and master/slave servers:
|
214
|
+
|
215
|
+
DB.extension :server_block
|
216
|
+
DB.with_server(:a, :a_read_only) do
|
217
|
+
# this SELECT query uses the "a_read_only" shard
|
218
|
+
if r = Rainbow.first(hash: /31337/)
|
219
|
+
r.count += 1
|
220
|
+
# this UPDATE query also uses the "a" shard
|
221
|
+
r.save
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
212
225
|
=== arbitrary_servers Extension
|
213
226
|
|
214
227
|
By default, Sequel's sharding support is designed to work with predefined shards. It ships
|
@@ -220,13 +233,13 @@ The arbitrary_servers extension allows you to pass a server/shard options hash a
|
|
220
233
|
server to use, and those options will be merged directly into the database's default options:
|
221
234
|
|
222
235
|
DB.extension :arbitrary_servers
|
223
|
-
DB[:rainbows].server(:
|
236
|
+
DB[:rainbows].server(host: 'hash_host_a').all
|
224
237
|
# or
|
225
|
-
DB[:rainbows].server(:
|
238
|
+
DB[:rainbows].server(host: 'hash_host_b', database: 'backup').all
|
226
239
|
|
227
240
|
arbitrary_servers is designed to work well in conjunction with the server_block extension:
|
228
241
|
|
229
|
-
DB.with_server(:
|
242
|
+
DB.with_server(host: 'hash_host_b', database: 'backup') do
|
230
243
|
DB.synchronize do
|
231
244
|
# All queries here default to the backup database on hash_host_b
|
232
245
|
end
|