sequel 4.49.0 → 5.3.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 +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/querying.rdoc
CHANGED
|
@@ -4,15 +4,15 @@ This guide is based on http://guides.rubyonrails.org/active_record_querying.html
|
|
|
4
4
|
|
|
5
5
|
== Purpose of this Guide
|
|
6
6
|
|
|
7
|
-
Sequel is a
|
|
7
|
+
Sequel is a flexible and powerful database library
|
|
8
8
|
that supports a wide variety of different querying methods. This guide
|
|
9
|
-
aims to be a
|
|
9
|
+
aims to be a introduction to Sequel's querying support.
|
|
10
10
|
|
|
11
|
-
While you can
|
|
11
|
+
While you can use raw SQL with Sequel, a large part of the
|
|
12
12
|
advantage you get from using Sequel is Sequel's ability to abstract
|
|
13
|
-
SQL from you and give you a
|
|
13
|
+
SQL from you and give you a pure-ruby interface. Sequel also ships with
|
|
14
14
|
a {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
15
|
-
which
|
|
15
|
+
which adds methods to core ruby types to work with Sequel.
|
|
16
16
|
|
|
17
17
|
== Retrieving Objects
|
|
18
18
|
|
|
@@ -39,7 +39,7 @@ by its primary key value:
|
|
|
39
39
|
|
|
40
40
|
# Find artist with primary key (id) 1
|
|
41
41
|
artist = Artist[1]
|
|
42
|
-
# SELECT * FROM artists WHERE id = 1
|
|
42
|
+
# SELECT * FROM artists WHERE (id = 1)
|
|
43
43
|
# => #<Artist @values={:name=>"YJM", :id=>1}>
|
|
44
44
|
|
|
45
45
|
If there is no record with the given primary key, nil will be returned. If you want
|
|
@@ -58,7 +58,7 @@ If you just want the first record in the dataset,
|
|
|
58
58
|
|
|
59
59
|
Any options you pass to +first+ will be used as a filter:
|
|
60
60
|
|
|
61
|
-
artist = Artist.first(:
|
|
61
|
+
artist = Artist.first(name: 'YJM')
|
|
62
62
|
# SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
|
|
63
63
|
# => #<Artist @values={:name=>"YJM", :id=>1}>
|
|
64
64
|
|
|
@@ -72,7 +72,7 @@ raise an exception instead, use <tt>first!</tt>.
|
|
|
72
72
|
<tt>Sequel::Dataset#[]</tt> is basically an alias for +first+, except it
|
|
73
73
|
requires an argument:
|
|
74
74
|
|
|
75
|
-
DB[:artists][:
|
|
75
|
+
DB[:artists][{name: 'YJM'}]
|
|
76
76
|
# SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
|
|
77
77
|
# => {:name=>"YJM", :id=>1}
|
|
78
78
|
|
|
@@ -109,6 +109,15 @@ you want:
|
|
|
109
109
|
# SELECT name FROM artists LIMIT 1
|
|
110
110
|
# => "YJM"
|
|
111
111
|
|
|
112
|
+
==== Retrieving a Multiple Column Values
|
|
113
|
+
|
|
114
|
+
If you want the value for multiple columns, you can pass an array to
|
|
115
|
+
<tt>Sequel::Dataset#get</tt>:
|
|
116
|
+
|
|
117
|
+
artist_id, artist_name, = Artist.get([:id, :name])
|
|
118
|
+
# SELECT name FROM artists LIMIT 1
|
|
119
|
+
# => [1, "YJM"]
|
|
120
|
+
|
|
112
121
|
=== Retrieving Multiple Objects
|
|
113
122
|
|
|
114
123
|
==== As an Array of Hashes or Model Objects
|
|
@@ -181,21 +190,21 @@ an array of arrays of values will be returned:
|
|
|
181
190
|
==== As a Hash
|
|
182
191
|
|
|
183
192
|
Sequel makes it easy to take an SQL query and return it as a ruby hash,
|
|
184
|
-
using the +
|
|
193
|
+
using the +as_hash+ method:
|
|
185
194
|
|
|
186
|
-
artist_names = Artist.
|
|
195
|
+
artist_names = Artist.as_hash(:id, :name)
|
|
187
196
|
# SELECT * FROM artists
|
|
188
197
|
# => {1=>"YJM", 2=>"AS"}
|
|
189
198
|
|
|
190
|
-
As you can see, the +
|
|
199
|
+
As you can see, the +as_hash+ method uses the first symbol as the key
|
|
191
200
|
and the second symbol as the value. So if you swap the two arguments the hash
|
|
192
201
|
will have its keys and values transposed:
|
|
193
202
|
|
|
194
|
-
artist_names = Artist.
|
|
203
|
+
artist_names = Artist.as_hash(:name, :id)
|
|
195
204
|
# SELECT * FROM artists
|
|
196
205
|
# => {"YJM"=>1, "AS"=>2}
|
|
197
206
|
|
|
198
|
-
Now what if you have multiple values for the same key? By default, +
|
|
207
|
+
Now what if you have multiple values for the same key? By default, +as_hash+
|
|
199
208
|
will just have the last matching value. If you care about all matching values,
|
|
200
209
|
use +to_hash_groups+, which makes the values of the array an array of matching
|
|
201
210
|
values, in the order they were received:
|
|
@@ -204,10 +213,10 @@ values, in the order they were received:
|
|
|
204
213
|
# SELECT * FROM artists
|
|
205
214
|
# => {"YJM"=>[1, 10, ...], "AS"=>[2, 20, ...]}
|
|
206
215
|
|
|
207
|
-
If you only provide one argument to +
|
|
216
|
+
If you only provide one argument to +as_hash+, it uses the entire hash
|
|
208
217
|
or model object as the value:
|
|
209
218
|
|
|
210
|
-
artist_names = DB[:artists].
|
|
219
|
+
artist_names = DB[:artists].as_hash(:name)
|
|
211
220
|
# SELECT * FROM artists
|
|
212
221
|
# => {"YJM"=>{:id=>1, :name=>"YJM"}, "AS"=>{:id=>2, :name=>"AS"}}
|
|
213
222
|
|
|
@@ -217,12 +226,12 @@ and +to_hash_groups+ works similarly:
|
|
|
217
226
|
# SELECT * FROM artists
|
|
218
227
|
# => {"YJM"=>[{:id=>1, :name=>"YJM"}, {:id=>10, :name=>"YJM"}], ...}
|
|
219
228
|
|
|
220
|
-
Model datasets have a +
|
|
229
|
+
Model datasets have a +as_hash+ method that can be called without any
|
|
221
230
|
arguments, in which case it will use the primary key as the key and
|
|
222
231
|
the model object as the value. This can be used to easily create an
|
|
223
232
|
identity map:
|
|
224
233
|
|
|
225
|
-
artist_names = Artist.
|
|
234
|
+
artist_names = Artist.as_hash
|
|
226
235
|
# SELECT * FROM artists
|
|
227
236
|
# => {1=>#<Artist @values={:id=>1, :name=>"YGM"}>,
|
|
228
237
|
# 2=>#<Artist @values={:id=>2, :name=>"AS"}>}
|
|
@@ -230,7 +239,7 @@ identity map:
|
|
|
230
239
|
There is no equivalent handling to +to_hash_groups+, since there would
|
|
231
240
|
only be one matching record, as the primary key must be unique.
|
|
232
241
|
|
|
233
|
-
Note that +
|
|
242
|
+
Note that +as_hash+ never modifies the columns selected. However, just
|
|
234
243
|
like Sequel has a +select_map+ method to modify the columns selected and
|
|
235
244
|
return an array, Sequel also has a +select_hash+ method to modify the
|
|
236
245
|
columns selected and return a hash:
|
|
@@ -260,8 +269,8 @@ be using:
|
|
|
260
269
|
1. Methods that return row(s), discussed above
|
|
261
270
|
2. Methods that return modified datasets, discussed below
|
|
262
271
|
|
|
263
|
-
Sequel
|
|
264
|
-
|
|
272
|
+
Sequel datasets are frozen and use a method chaining, functional style API
|
|
273
|
+
that returns modified datasets. Let's start with a simple example.
|
|
265
274
|
|
|
266
275
|
This is a basic dataset that includes all records in the
|
|
267
276
|
table +artists+:
|
|
@@ -273,7 +282,7 @@ Let's say we are only interested in the artists whose names
|
|
|
273
282
|
start with "A":
|
|
274
283
|
|
|
275
284
|
ds2 = ds1.where(Sequel.like(:name, 'A%'))
|
|
276
|
-
# SELECT * FROM artists WHERE name LIKE 'A%' ESCAPE '\'
|
|
285
|
+
# SELECT * FROM artists WHERE (name LIKE 'A%' ESCAPE '\')
|
|
277
286
|
|
|
278
287
|
Here we see that +where+ returns a dataset that adds a +WHERE+
|
|
279
288
|
clause to the query. It's important to note that +where+ does
|
|
@@ -282,10 +291,9 @@ not modify the receiver:
|
|
|
282
291
|
ds1
|
|
283
292
|
# SELECT * FROM artists
|
|
284
293
|
ds2
|
|
285
|
-
# SELECT * FROM artists WHERE name LIKE 'A%' ESCAPE '\'
|
|
294
|
+
# SELECT * FROM artists WHERE (name LIKE 'A%' ESCAPE '\')
|
|
286
295
|
|
|
287
|
-
In Sequel,
|
|
288
|
-
not modify the dataset itself, so you can freely use the dataset in multiple
|
|
296
|
+
In Sequel, dataset methods do not modify the dataset itself, so you can freely use the dataset in multiple
|
|
289
297
|
places without worrying that its usage in one place will affect its usage
|
|
290
298
|
in another place. This is what is meant by a functional style API.
|
|
291
299
|
|
|
@@ -293,7 +301,7 @@ Let's say we only want to select the id and name columns, and that
|
|
|
293
301
|
we want to order by name:
|
|
294
302
|
|
|
295
303
|
ds3 = ds2.order(:name).select(:id, :name)
|
|
296
|
-
# SELECT id, name FROM artists WHERE name LIKE 'A%' ESCAPE '\' ORDER BY name
|
|
304
|
+
# SELECT id, name FROM artists WHERE (name LIKE 'A%' ESCAPE '\') ORDER BY name
|
|
297
305
|
|
|
298
306
|
Note how you don't need to assign the returned value of order to a variable,
|
|
299
307
|
and then call select on that. Because order just returns a dataset, you can
|
|
@@ -315,54 +323,57 @@ below.
|
|
|
315
323
|
=== Hashes
|
|
316
324
|
|
|
317
325
|
The most common format for providing filters is via a hash. In general, Sequel
|
|
318
|
-
treats conditions specified with a hash as equality or
|
|
326
|
+
treats conditions specified with a hash as equality, inclusion, or identity. What type
|
|
319
327
|
of condition is used depends on the values in the hash.
|
|
320
328
|
|
|
321
329
|
Unless Sequel has special support for the value's class, it uses a simple
|
|
322
330
|
equality statement:
|
|
323
331
|
|
|
324
|
-
Artist.where(:
|
|
325
|
-
# SELECT * FROM artists WHERE id = 1
|
|
332
|
+
Artist.where(id: 1)
|
|
333
|
+
# SELECT * FROM artists WHERE (id = 1)
|
|
326
334
|
|
|
327
|
-
Artist.where(:
|
|
328
|
-
# SELECT * FROM artists WHERE name = 'YJM'
|
|
335
|
+
Artist.where(name: 'YJM')
|
|
336
|
+
# SELECT * FROM artists WHERE (name = 'YJM')
|
|
329
337
|
|
|
330
|
-
For arrays, Sequel uses the IN operator
|
|
338
|
+
For arrays, Sequel uses the IN operator with a value list:
|
|
331
339
|
|
|
332
|
-
Artist.where(:
|
|
333
|
-
# SELECT * FROM artists WHERE id IN (1, 2)
|
|
340
|
+
Artist.where(id: [1, 2])
|
|
341
|
+
# SELECT * FROM artists WHERE (id IN (1, 2))
|
|
334
342
|
|
|
335
343
|
For datasets, Sequel uses the IN operator with a subselect:
|
|
336
344
|
|
|
337
|
-
Artist.where(:
|
|
338
|
-
# SELECT * FROM artists WHERE id IN (
|
|
339
|
-
# SELECT artist_id FROM albums)
|
|
345
|
+
Artist.where(id: Album.select(:artist_id))
|
|
346
|
+
# SELECT * FROM artists WHERE (id IN (
|
|
347
|
+
# SELECT artist_id FROM albums))
|
|
340
348
|
|
|
341
349
|
For boolean values such as nil, true, and false, Sequel uses the IS operator:
|
|
342
350
|
|
|
343
|
-
Artist.where(:
|
|
344
|
-
# SELECT * FROM artists WHERE id IS NULL
|
|
351
|
+
Artist.where(id: nil)
|
|
352
|
+
# SELECT * FROM artists WHERE (id IS NULL)
|
|
345
353
|
|
|
346
354
|
For ranges, Sequel uses a pair of inequality statements:
|
|
347
355
|
|
|
348
|
-
Artist.where(:
|
|
349
|
-
# SELECT * FROM artists WHERE id >= 1 AND id <= 5
|
|
356
|
+
Artist.where(id: 1..5)
|
|
357
|
+
# SELECT * FROM artists WHERE ((id >= 1) AND (id <= 5))
|
|
358
|
+
|
|
359
|
+
Artist.where(id: 1...5)
|
|
360
|
+
# SELECT * FROM artists WHERE ((id >= 1) AND (id < 5))
|
|
350
361
|
|
|
351
362
|
Finally, for regexps, Sequel uses an SQL regular expression. Note that this
|
|
352
363
|
is probably only supported on PostgreSQL and MySQL.
|
|
353
364
|
|
|
354
|
-
Artist.where(:
|
|
355
|
-
# SELECT * FROM artists WHERE name ~ 'JM$'
|
|
365
|
+
Artist.where(name: /JM$/)
|
|
366
|
+
# SELECT * FROM artists WHERE (name ~ 'JM$')
|
|
356
367
|
|
|
357
368
|
If there are multiple arguments in the hash, the filters are ANDed together:
|
|
358
369
|
|
|
359
|
-
Artist.where(:
|
|
360
|
-
# SELECT * FROM artists WHERE id = 1 AND name ~ 'JM$'
|
|
370
|
+
Artist.where(id: 1, name: /JM$/)
|
|
371
|
+
# SELECT * FROM artists WHERE ((id = 1) AND (name ~ 'JM$'))
|
|
361
372
|
|
|
362
373
|
This works the same as if you used two separate +where+ calls:
|
|
363
374
|
|
|
364
|
-
Artist.where(:
|
|
365
|
-
# SELECT * FROM artists WHERE id = 1 AND name ~ 'JM$'
|
|
375
|
+
Artist.where(id: 1).where(name: /JM$/)
|
|
376
|
+
# SELECT * FROM artists WHERE ((id = 1) AND (name ~ 'JM$'))
|
|
366
377
|
|
|
367
378
|
=== Array of Two Element Arrays
|
|
368
379
|
|
|
@@ -371,28 +382,28 @@ advantage to using an array of two element arrays is that it allows you to
|
|
|
371
382
|
duplicate keys, so you can do:
|
|
372
383
|
|
|
373
384
|
Artist.where([[:name, /JM$/], [:name, /^YJ/]])
|
|
374
|
-
# SELECT * FROM artists WHERE name ~ 'JM$' AND name ~ '^YJ'
|
|
385
|
+
# SELECT * FROM artists WHERE ((name ~ 'JM$')) AND ((name ~ '^YJ'))
|
|
375
386
|
|
|
376
387
|
=== Virtual Row Blocks
|
|
377
388
|
|
|
378
389
|
If a block is passed to a filter, it is treated as a virtual row block:
|
|
379
390
|
|
|
380
391
|
Artist.where{id > 5}
|
|
381
|
-
# SELECT * FROM artists WHERE id > 5
|
|
392
|
+
# SELECT * FROM artists WHERE (id > 5)
|
|
382
393
|
|
|
383
394
|
You can learn more about virtual row blocks in the {"Virtual Rows" guide}[rdoc-ref:doc/virtual_rows.rdoc].
|
|
384
395
|
|
|
385
396
|
You can provide both regular arguments and a block, in which case the results
|
|
386
397
|
will be ANDed together:
|
|
387
398
|
|
|
388
|
-
Artist.where(:
|
|
389
|
-
# SELECT * FROM artists WHERE name >= 'A' AND name < 'M' AND id > 5
|
|
399
|
+
Artist.where(name: 'A'...'M'){id > 5}
|
|
400
|
+
# SELECT * FROM artists WHERE ((name >= 'A') AND (name < 'M') AND (id > 5))
|
|
390
401
|
|
|
391
402
|
Using virtual row blocks, what you can do with single entry hash or an array with
|
|
392
403
|
a single two element array can also be done using the =~ method:
|
|
393
404
|
|
|
394
405
|
Artist.where{id =~ 5}
|
|
395
|
-
# SELECT * FROM artists WHERE id = 5
|
|
406
|
+
# SELECT * FROM artists WHERE (id = 5)
|
|
396
407
|
|
|
397
408
|
=== Symbols
|
|
398
409
|
|
|
@@ -420,43 +431,44 @@ method is Sequel.[], which takes any object and wraps it in a SQL::Expression
|
|
|
420
431
|
object. In most cases, the SQL::Expression returned supports the & operator for
|
|
421
432
|
+AND+, the | operator for +OR+, and the ~ operator for inversion:
|
|
422
433
|
|
|
423
|
-
Artist.where(Sequel.like(:name, 'Y%') & (Sequel[:
|
|
424
|
-
# SELECT * FROM artists WHERE name LIKE 'Y%' ESCAPE '\' AND (b = 1 OR c != 3)
|
|
434
|
+
Artist.where(Sequel.like(:name, 'Y%') & (Sequel[{b: 1}] | Sequel.~(c: 3)))
|
|
435
|
+
# SELECT * FROM artists WHERE ((name LIKE 'Y%' ESCAPE '\') AND ((b = 1) OR (c != 3)))
|
|
425
436
|
|
|
426
437
|
You can combine these expression operators with the virtual row support:
|
|
427
438
|
|
|
428
439
|
Artist.where{(a > 1) & ~((b(c) < 1) | d)}
|
|
429
|
-
# SELECT * FROM artists WHERE a > 1 AND b(c) >= 1 AND NOT d
|
|
440
|
+
# SELECT * FROM artists WHERE ((a > 1) AND (b(c) >= 1) AND NOT d)
|
|
430
441
|
|
|
431
442
|
Note the use of parentheses when using the & and | operators, as they have lower
|
|
432
443
|
precedence than other operators. The following will not work:
|
|
433
444
|
|
|
434
445
|
Artist.where{a > 1 & ~(b(c) < 1 | d)}
|
|
435
|
-
# Raises a TypeError
|
|
446
|
+
# Raises a TypeError
|
|
436
447
|
|
|
437
448
|
=== Strings with Placeholders
|
|
438
449
|
|
|
439
|
-
Assuming you want to get your hands dirty and
|
|
440
|
-
to
|
|
450
|
+
Assuming you want to get your hands dirty and use SQL fragments in filters, Sequel allows you
|
|
451
|
+
to do so if you explicitly mark the strings as literal strings using +Sequel.lit+. You can
|
|
452
|
+
use placeholders in the string and pass arguments for the placeholders:
|
|
441
453
|
|
|
442
|
-
Artist.where("name LIKE ?", 'Y%')
|
|
443
|
-
# SELECT * FROM artists WHERE name LIKE 'Y%'
|
|
454
|
+
Artist.where(Sequel.lit("name LIKE ?", 'Y%'))
|
|
455
|
+
# SELECT * FROM artists WHERE (name LIKE 'Y%')
|
|
444
456
|
|
|
445
457
|
This is the most common type of placeholder, where each question mark is substituted
|
|
446
458
|
with the next argument:
|
|
447
459
|
|
|
448
|
-
Artist.where("name LIKE ? AND id = ?", 'Y%', 5)
|
|
449
|
-
# SELECT * FROM artists WHERE name LIKE 'Y%' AND id = 5
|
|
460
|
+
Artist.where(Sequel.lit("name LIKE ? AND id = ?", 'Y%', 5))
|
|
461
|
+
# SELECT * FROM artists WHERE (name LIKE 'Y%' AND id = 5)
|
|
450
462
|
|
|
451
463
|
You can also use named placeholders with a hash, where the named placeholders use
|
|
452
464
|
colons before the placeholder names:
|
|
453
465
|
|
|
454
|
-
Artist.where("name LIKE :name AND id = :id", :
|
|
455
|
-
# SELECT * FROM artists WHERE name LIKE 'Y%' AND id = 5
|
|
466
|
+
Artist.where(Sequel.lit("name LIKE :name AND id = :id", name: 'Y%', id: 5))
|
|
467
|
+
# SELECT * FROM artists WHERE (name LIKE 'Y%' AND id = 5)
|
|
456
468
|
|
|
457
469
|
You don't have to provide any placeholders if you don't want to:
|
|
458
470
|
|
|
459
|
-
Artist.where("id = 2")
|
|
471
|
+
Artist.where(Sequel.lit("id = 2"))
|
|
460
472
|
# SELECT * FROM artists WHERE id = 2
|
|
461
473
|
|
|
462
474
|
However, if you are using any untrusted input, you should definitely be using placeholders.
|
|
@@ -464,9 +476,9 @@ In general, unless you are hardcoding values in the strings, you should use plac
|
|
|
464
476
|
You should never pass a string that has been built using interpolation, unless you are
|
|
465
477
|
sure of what you are doing.
|
|
466
478
|
|
|
467
|
-
Artist.where("id = #{params[:id]}") # Don't do this!
|
|
468
|
-
Artist.where("id = ?", params[:id]) # Do this instead
|
|
469
|
-
Artist.where(:
|
|
479
|
+
Artist.where(Sequel.lit("id = #{params[:id]}")) # Don't do this!
|
|
480
|
+
Artist.where(Sequel.lit("id = ?", params[:id])) # Do this instead
|
|
481
|
+
Artist.where(id: params[:id].to_i) # Even better
|
|
470
482
|
|
|
471
483
|
=== Inverting
|
|
472
484
|
|
|
@@ -474,53 +486,53 @@ You may be wondering how to specify a not equals condition in Sequel, or the NOT
|
|
|
474
486
|
operator. Sequel has generic support for inverting conditions, so to write a not
|
|
475
487
|
equals condition, you write an equals condition, and invert it:
|
|
476
488
|
|
|
477
|
-
Artist.where(:
|
|
478
|
-
# SELECT * FROM artists WHERE id != 5
|
|
489
|
+
Artist.where(id: 5).invert
|
|
490
|
+
# SELECT * FROM artists WHERE (id != 5)
|
|
479
491
|
|
|
480
492
|
Note that +invert+ inverts the entire filter:
|
|
481
493
|
|
|
482
|
-
Artist.where(:
|
|
483
|
-
# SELECT * FROM artists WHERE id != 5 OR name <= 'A'
|
|
494
|
+
Artist.where(id: 5).where{name > 'A'}.invert
|
|
495
|
+
# SELECT * FROM artists WHERE ((id != 5) OR (name <= 'A'))
|
|
484
496
|
|
|
485
497
|
In general, +invert+ is used rarely, since +exclude+ allows you to invert only specific
|
|
486
498
|
filters:
|
|
487
499
|
|
|
488
|
-
Artist.exclude(:
|
|
489
|
-
# SELECT * FROM artists WHERE id != 5
|
|
500
|
+
Artist.exclude(id: 5)
|
|
501
|
+
# SELECT * FROM artists WHERE (id != 5)
|
|
490
502
|
|
|
491
|
-
Artist.where(:
|
|
492
|
-
# SELECT * FROM artists WHERE id = 5 OR name <= 'A'
|
|
503
|
+
Artist.where(id: 5).exclude{name > 'A'}
|
|
504
|
+
# SELECT * FROM artists WHERE ((id = 5) OR (name <= 'A')
|
|
493
505
|
|
|
494
506
|
So to do a NOT IN with an array:
|
|
495
507
|
|
|
496
|
-
Artist.exclude(:
|
|
497
|
-
# SELECT * FROM artists WHERE id NOT IN (1, 2)
|
|
508
|
+
Artist.exclude(id: [1, 2])
|
|
509
|
+
# SELECT * FROM artists WHERE (id NOT IN (1, 2))
|
|
498
510
|
|
|
499
511
|
Or to use the NOT LIKE operator:
|
|
500
512
|
|
|
501
513
|
Artist.exclude(Sequel.like(:name, '%J%'))
|
|
502
|
-
# SELECT * FROM artists WHERE name NOT LIKE '%J%' ESCAPE '\'
|
|
514
|
+
# SELECT * FROM artists WHERE (name NOT LIKE '%J%' ESCAPE '\')
|
|
503
515
|
|
|
504
516
|
You can use Sequel.~ to negate expressions:
|
|
505
517
|
|
|
506
|
-
Artist.where(Sequel.~(:
|
|
518
|
+
Artist.where(Sequel.~(id: 5))
|
|
507
519
|
# SELECT * FROM artists WHERE id != 5
|
|
508
520
|
|
|
509
521
|
On Sequel expression objects, you can use ~ to negate them:
|
|
510
522
|
|
|
511
523
|
Artist.where(~Sequel.like(:name, '%J%'))
|
|
512
|
-
# SELECT * FROM artists WHERE name NOT LIKE '%J%' ESCAPE '\'
|
|
524
|
+
# SELECT * FROM artists WHERE (name NOT LIKE '%J%' ESCAPE '\')
|
|
513
525
|
|
|
514
|
-
|
|
526
|
+
You can use !~ on Sequel expressions to create negated expressions:
|
|
515
527
|
|
|
516
|
-
Artist.where{
|
|
517
|
-
# SELECT * FROM artists WHERE id != 5
|
|
528
|
+
Artist.where{id !~ 5}
|
|
529
|
+
# SELECT * FROM artists WHERE (id != 5)
|
|
518
530
|
|
|
519
531
|
=== Removing
|
|
520
532
|
|
|
521
533
|
To remove all existing filters, use +unfiltered+:
|
|
522
534
|
|
|
523
|
-
Artist.where(:
|
|
535
|
+
Artist.where(id: 1).unfiltered
|
|
524
536
|
# SELECT * FROM artists
|
|
525
537
|
|
|
526
538
|
== Ordering
|
|
@@ -555,14 +567,17 @@ If you want to add a column to the beginning of the existing order:
|
|
|
555
567
|
=== Reversing
|
|
556
568
|
|
|
557
569
|
Just like you can invert an existing filter, you can reverse an existing
|
|
558
|
-
order, using +reverse
|
|
570
|
+
order, using +reverse+ without an order:
|
|
559
571
|
|
|
560
572
|
Artist.order(:id).reverse
|
|
561
573
|
# SELECT FROM artists ORDER BY id DESC
|
|
562
574
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
575
|
+
Alternatively, you can provide reverse with the order:
|
|
576
|
+
|
|
577
|
+
Artist.reverse(:id)
|
|
578
|
+
# SELECT FROM artists ORDER BY id DESC
|
|
579
|
+
|
|
580
|
+
To specify a single entry be reversed, <tt>Sequel.desc</tt> can be used:
|
|
566
581
|
|
|
567
582
|
Artist.order(Sequel.desc(:id))
|
|
568
583
|
# SELECT FROM artists ORDER BY id DESC
|
|
@@ -658,7 +673,7 @@ You can also call the +offset+ method separately:
|
|
|
658
673
|
Either of these would return the 11th through 15th records in the original
|
|
659
674
|
dataset.
|
|
660
675
|
|
|
661
|
-
To remove a limit from a dataset, use +unlimited+:
|
|
676
|
+
To remove a limit and offset from a dataset, use +unlimited+:
|
|
662
677
|
|
|
663
678
|
Artist.limit(5, 10).unlimited
|
|
664
679
|
# SELECT * FROM artists
|
|
@@ -709,50 +724,46 @@ filters the results after the grouping has been applied, instead of
|
|
|
709
724
|
before. One possible use is if you only wanted to return artists
|
|
710
725
|
who had at least 10 albums:
|
|
711
726
|
|
|
712
|
-
Album.group_and_count(:artist_id).having{count
|
|
727
|
+
Album.group_and_count(:artist_id).having{count.function.* >= 10}
|
|
713
728
|
# SELECT artist_id, count(*) AS count FROM albums
|
|
714
|
-
# GROUP BY artist_id HAVING count(*) >= 10
|
|
729
|
+
# GROUP BY artist_id HAVING (count(*) >= 10)
|
|
715
730
|
|
|
716
731
|
Both the WHERE clause and the HAVING clause are removed by +unfiltered+:
|
|
717
732
|
|
|
718
|
-
Album.group_and_count(:artist_id).having{count
|
|
733
|
+
Album.group_and_count(:artist_id).having{count.function.* >= 10}.
|
|
719
734
|
where(:name.like('A%')).unfiltered
|
|
720
735
|
# SELECT artist_id, count(*) AS count FROM albums GROUP BY artist_id
|
|
721
736
|
|
|
722
737
|
== Joins
|
|
723
738
|
|
|
724
|
-
Sequel
|
|
739
|
+
Sequel has support for many different SQL join types.
|
|
725
740
|
The underlying method used is +join_table+:
|
|
726
741
|
|
|
727
|
-
Album.join_table(:inner, :artists, :
|
|
742
|
+
Album.join_table(:inner, :artists, id: :artist_id)
|
|
728
743
|
# SELECT * FROM albums
|
|
729
|
-
# INNER JOIN artists ON artists.id = albums.artist_id
|
|
744
|
+
# INNER JOIN artists ON (artists.id = albums.artist_id)
|
|
730
745
|
|
|
731
746
|
In most cases, you won't call +join_table+ directly, as Sequel provides
|
|
732
747
|
shortcuts for all common (and most uncommon) join types. For example
|
|
733
748
|
+join+ does an inner join:
|
|
734
749
|
|
|
735
|
-
Album.join(:artists, :
|
|
750
|
+
Album.join(:artists, id: :artist_id)
|
|
736
751
|
# SELECT * FROM albums
|
|
737
|
-
# INNER JOIN artists ON artists.id = albums.artist_id
|
|
752
|
+
# INNER JOIN artists ON (artists.id = albums.artist_id))))
|
|
738
753
|
|
|
739
754
|
And +left_join+ does a LEFT JOIN:
|
|
740
755
|
|
|
741
|
-
Album.left_join(:artists, :
|
|
756
|
+
Album.left_join(:artists, id: :artist_id)
|
|
742
757
|
# SELECT * FROM albums
|
|
743
|
-
# LEFT JOIN artists ON artists.id = albums.artist_id
|
|
758
|
+
# LEFT JOIN artists ON (artists.id = albums.artist_id)
|
|
744
759
|
|
|
745
760
|
=== Table/Dataset to Join
|
|
746
761
|
|
|
747
762
|
For all of these specialized join methods, the first argument is
|
|
748
763
|
generally the name of the table to which you are joining. However, you
|
|
749
|
-
can also provide a
|
|
750
|
-
|
|
751
|
-
Album.join(Artist, :id=>:artist_id)
|
|
752
|
-
|
|
753
|
-
Or a dataset, in which case a subselect is used:
|
|
764
|
+
can also provide a dataset, in which case a subselect is used:
|
|
754
765
|
|
|
755
|
-
Album.join(Artist.where{name < 'A'}, :
|
|
766
|
+
Album.join(Artist.where{name < 'A'}, id: :artist_id)
|
|
756
767
|
# SELECT * FROM albums
|
|
757
768
|
# INNER JOIN (SELECT * FROM artists WHERE (name < 'A')) AS t1
|
|
758
769
|
# ON (t1.id = albums.artist_id)
|
|
@@ -768,80 +779,78 @@ a few minor exceptions.
|
|
|
768
779
|
A hash used as the join conditions operates similarly to a filter,
|
|
769
780
|
except that unqualified symbol keys are automatically qualified
|
|
770
781
|
with the table from the first argument, and unqualified symbol values
|
|
771
|
-
are automatically qualified with the
|
|
772
|
-
|
|
773
|
-
in Sequel are easy to specify:
|
|
782
|
+
are automatically qualified with the last table joined (or the first
|
|
783
|
+
table in the dataset if there hasn't been a previous join):
|
|
774
784
|
|
|
775
|
-
Album.join(:artists, :
|
|
785
|
+
Album.join(:artists, id: :artist_id)
|
|
776
786
|
# SELECT * FROM albums
|
|
777
|
-
# INNER JOIN artists ON artists.id = albums.artist_id
|
|
787
|
+
# INNER JOIN artists ON (artists.id = albums.artist_id)
|
|
778
788
|
|
|
779
|
-
Note how the
|
|
789
|
+
Note how the +id+ symbol is automatically qualified with +artists+,
|
|
780
790
|
while the +artist_id+ symbol is automatically qualified with +albums+.
|
|
781
791
|
|
|
782
792
|
Because Sequel uses the last joined table for implicit qualifications
|
|
783
793
|
of values, you can do things like:
|
|
784
794
|
|
|
785
|
-
Album.join(:artists, :
|
|
786
|
-
join(:members, :
|
|
795
|
+
Album.join(:artists, id: :artist_id).
|
|
796
|
+
join(:members, artist_id: :id)
|
|
787
797
|
# SELECT * FROM albums
|
|
788
|
-
# INNER JOIN artists ON artists.id = albums.artist_id
|
|
789
|
-
# INNER JOIN members ON members.artist_id = artists.id
|
|
798
|
+
# INNER JOIN artists ON (artists.id = albums.artist_id)
|
|
799
|
+
# INNER JOIN members ON (members.artist_id = artists.id)
|
|
790
800
|
|
|
791
801
|
Note that when joining to the +members+ table, +artist_id+ is qualified
|
|
792
802
|
with +members+ and +id+ is qualified with +artists+.
|
|
793
803
|
|
|
794
804
|
While a good default, implicit qualification is not always correct:
|
|
795
805
|
|
|
796
|
-
Album.join(:artists, :
|
|
797
|
-
join(:tracks, :
|
|
806
|
+
Album.join(:artists, id: :artist_id).
|
|
807
|
+
join(:tracks, album_id: :id)
|
|
798
808
|
# SELECT * FROM albums
|
|
799
|
-
# INNER JOIN artists ON artists.id = albums.artist_id
|
|
800
|
-
# INNER JOIN tracks ON tracks.album_id = artists.id
|
|
809
|
+
# INNER JOIN artists ON (artists.id = albums.artist_id)
|
|
810
|
+
# INNER JOIN tracks ON (tracks.album_id = artists.id)
|
|
801
811
|
|
|
802
812
|
Note here how +id+ is qualified with +artists+ instead of +albums+. This
|
|
803
813
|
is wrong as the foreign key <tt>tracks.album_id</tt> refers to <tt>albums.id</tt>, not
|
|
804
814
|
<tt>artists.id</tt>. To fix this, you need to explicitly qualify when joining:
|
|
805
815
|
|
|
806
|
-
Album.join(:artists, :
|
|
807
|
-
join(:tracks, :
|
|
816
|
+
Album.join(:artists, id: :artist_id).
|
|
817
|
+
join(:tracks, album_id: Sequel[:albums][:id])
|
|
808
818
|
# SELECT * FROM albums
|
|
809
|
-
# INNER JOIN artists ON artists.id = albums.artist_id
|
|
810
|
-
# INNER JOIN tracks ON tracks.album_id = albums.id
|
|
819
|
+
# INNER JOIN artists ON (artists.id = albums.artist_id)
|
|
820
|
+
# INNER JOIN tracks ON (tracks.album_id = albums.id)
|
|
811
821
|
|
|
812
822
|
Just like in filters, an array of two element arrays is treated the same
|
|
813
823
|
as a hash, but allows for duplicate keys:
|
|
814
824
|
|
|
815
825
|
Album.join(:artists, [[:id, :artist_id], [:id, 1..5]])
|
|
816
826
|
# SELECT * FROM albums INNER JOIN artists
|
|
817
|
-
# ON artists.id = albums.artist_id
|
|
818
|
-
# AND artists.id >= 1 AND artists.id <= 5
|
|
827
|
+
# ON ((artists.id = albums.artist_id)
|
|
828
|
+
# AND (artists.id >= 1) AND (artists.id <= 5))
|
|
819
829
|
|
|
820
830
|
And just like in the hash case, unqualified symbol elements in the
|
|
821
831
|
array are implicitly qualified.
|
|
822
832
|
|
|
823
833
|
By default, Sequel only qualifies unqualified symbols in the conditions. However,
|
|
824
|
-
You can provide an options hash with a <tt
|
|
834
|
+
You can provide an options hash with a <tt>qualify: :deep</tt> option to do a deep
|
|
825
835
|
qualification, which can qualify subexpressions. For example, let's say you are doing
|
|
826
836
|
a JOIN using case insensitive string comparison:
|
|
827
837
|
|
|
828
838
|
Album.join(:artists, {Sequel.function(:lower, :name) =>
|
|
829
839
|
Sequel.function(:lower, :artist_name)},
|
|
830
|
-
:
|
|
840
|
+
qualify: :deep)
|
|
831
841
|
# SELECT * FROM albums INNER JOIN artists
|
|
832
842
|
# ON (lower(artists.name) = lower(albums.artist_name))
|
|
833
843
|
|
|
834
|
-
Note how the arguments to lower were qualified correctly in both cases.
|
|
835
|
-
the <tt>:qualify=>:deep</tt> option is going to become the default.
|
|
844
|
+
Note how the arguments to lower were qualified correctly in both cases.
|
|
836
845
|
|
|
837
846
|
==== USING Joins
|
|
838
847
|
|
|
839
848
|
The most common type of join conditions is a JOIN ON, as displayed
|
|
840
849
|
above. However, the SQL standard allows for join conditions to be
|
|
841
|
-
specified with JOIN USING,
|
|
850
|
+
specified with JOIN USING, assuming the column name is the same in
|
|
851
|
+
both tables.
|
|
842
852
|
|
|
843
|
-
|
|
844
|
-
names in both tables. For example, if instead of having a primary
|
|
853
|
+
For example, if instead of having a primary
|
|
845
854
|
column named +id+ in all of your tables, you use +artist_id+ in your
|
|
846
855
|
+artists+ table and +album_id+ in your +albums+ table, you could do:
|
|
847
856
|
|
|
@@ -852,7 +861,7 @@ See here how you specify the USING columns as an array of symbols.
|
|
|
852
861
|
|
|
853
862
|
==== NATURAL Joins
|
|
854
863
|
|
|
855
|
-
NATURAL
|
|
864
|
+
NATURAL joins take it one step further than USING joins, by assuming
|
|
856
865
|
that all columns with the same names in both tables should be
|
|
857
866
|
used for joining:
|
|
858
867
|
|
|
@@ -875,12 +884,12 @@ being used. For example, lets say you wanted to join the albums
|
|
|
875
884
|
and artists tables, but only want albums where the artist's name
|
|
876
885
|
comes before the album's name.
|
|
877
886
|
|
|
878
|
-
Album.join(:artists, :
|
|
887
|
+
Album.join(:artists, id: :artist_id) do |j, lj, js|
|
|
879
888
|
Sequel[j][:name] < Sequel[lj][:name]
|
|
880
889
|
end
|
|
881
890
|
# SELECT * FROM albums INNER JOIN artists
|
|
882
|
-
# ON artists.id = albums.artist_id
|
|
883
|
-
# AND artists.name < albums.name
|
|
891
|
+
# ON ((artists.id = albums.artist_id)
|
|
892
|
+
# AND (artists.name < albums.name))
|
|
884
893
|
|
|
885
894
|
Because greater than can't be expressed with a hash in Sequel, you
|
|
886
895
|
need to use a block and qualify the tables manually.
|
|
@@ -905,7 +914,7 @@ Using multiple FROM tables and setting conditions in the WHERE clause is
|
|
|
905
914
|
an old-school way of joining tables:
|
|
906
915
|
|
|
907
916
|
DB.from(:albums, :artists).where{{artists[:id]=>albums[:artist_id]}}
|
|
908
|
-
# SELECT * FROM albums, artists WHERE artists.id = albums.artist_id
|
|
917
|
+
# SELECT * FROM albums, artists WHERE (artists.id = albums.artist_id)
|
|
909
918
|
|
|
910
919
|
=== Using the current dataset in a subselect
|
|
911
920
|
|
|
@@ -916,7 +925,7 @@ Here's an example using +from_self+:
|
|
|
916
925
|
# SELECT * FROM (SELECT * FROM albums ORDER BY artist_id LIMIT 100)
|
|
917
926
|
# AS t1 GROUP BY artist_id
|
|
918
927
|
|
|
919
|
-
This is
|
|
928
|
+
This is different than without +from_self+:
|
|
920
929
|
|
|
921
930
|
Album.order(:artist_id).limit(100).group(:artist_id)
|
|
922
931
|
# SELECT * FROM albums GROUP BY artist_id ORDER BY name LIMIT 100
|
|
@@ -937,8 +946,8 @@ current transaction commits. You just use the +for_update+ dataset
|
|
|
937
946
|
method when returning the rows:
|
|
938
947
|
|
|
939
948
|
DB.transaction do
|
|
940
|
-
album = Album.for_update.first(:
|
|
941
|
-
# SELECT * FROM albums WHERE id = 1 FOR UPDATE
|
|
949
|
+
album = Album.for_update.first(id: 1)
|
|
950
|
+
# SELECT * FROM albums WHERE (id = 1) FOR UPDATE
|
|
942
951
|
album.num_tracks += 1
|
|
943
952
|
album.save
|
|
944
953
|
end
|
|
@@ -956,7 +965,7 @@ stateless nature.
|
|
|
956
965
|
|
|
957
966
|
== Custom SQL
|
|
958
967
|
|
|
959
|
-
Sequel makes it easy to use custom SQL by providing it to the <tt>Database#[]</tt>
|
|
968
|
+
Sequel makes it easy to use custom SQL for the query by providing it to the <tt>Database#[]</tt>
|
|
960
969
|
method as a string:
|
|
961
970
|
|
|
962
971
|
DB["SELECT * FROM artists"]
|
|
@@ -973,7 +982,7 @@ With either of these methods, you can use placeholders:
|
|
|
973
982
|
DB["SELECT * FROM artists WHERE id = ?", 5]
|
|
974
983
|
# SELECT * FROM artists WHERE id = 5
|
|
975
984
|
|
|
976
|
-
DB[:albums].with_sql("SELECT * FROM artists WHERE id = :id", :
|
|
985
|
+
DB[:albums].with_sql("SELECT * FROM artists WHERE id = :id", id: 5)
|
|
977
986
|
# SELECT * FROM artists WHERE id = 5
|
|
978
987
|
|
|
979
988
|
Note that if you specify the dataset using custom SQL, you can still call the dataset
|
|
@@ -982,6 +991,13 @@ modification methods, but in many cases they will appear to have no affect:
|
|
|
982
991
|
DB["SELECT * FROM artists"].select(:name).order(:id)
|
|
983
992
|
# SELECT * FROM artists
|
|
984
993
|
|
|
994
|
+
You can use the implicit_subquery extension to automatically wrap queries that use
|
|
995
|
+
custom SQL in subqueries if a method is called that would modify the SQL:
|
|
996
|
+
|
|
997
|
+
DB.extension :implicit_subquery
|
|
998
|
+
DB["SELECT * FROM artists"].select(:name).order(:id)
|
|
999
|
+
# SELECT name FROM (SELECT * FROM artists) AS t1 ORDER BY id"
|
|
1000
|
+
|
|
985
1001
|
If you must drop down to using custom SQL, it's recommended that you only do so for
|
|
986
1002
|
specific parts of a query. For example, if the reason you are using custom SQL is
|
|
987
1003
|
to use a custom operator in the database in the SELECT clause:
|
|
@@ -1003,12 +1019,12 @@ If you just want to know whether the current dataset would return any rows, use
|
|
|
1003
1019
|
# SELECT 1 FROM albums LIMIT 1
|
|
1004
1020
|
# => false
|
|
1005
1021
|
|
|
1006
|
-
Album.where(:
|
|
1007
|
-
# SELECT 1 FROM albums WHERE id = 0 LIMIT 1
|
|
1022
|
+
Album.where(id: 0).empty?
|
|
1023
|
+
# SELECT 1 FROM albums WHERE (id = 0) LIMIT 1
|
|
1008
1024
|
# => true
|
|
1009
1025
|
|
|
1010
1026
|
Album.where(Sequel.like(:name, 'R%')).empty?
|
|
1011
|
-
# SELECT 1 FROM albums WHERE name LIKE 'R%' ESCAPE '\' LIMIT 1
|
|
1027
|
+
# SELECT 1 FROM albums WHERE (name LIKE 'R%' ESCAPE '\') LIMIT 1
|
|
1012
1028
|
# => false
|
|
1013
1029
|
|
|
1014
1030
|
== Aggregate Calculations
|
|
@@ -1022,22 +1038,29 @@ for each of these aggregate functions.
|
|
|
1022
1038
|
Album.count
|
|
1023
1039
|
# SELECT count(*) AS count FROM albums LIMIT 1
|
|
1024
1040
|
# => 2
|
|
1025
|
-
|
|
1041
|
+
|
|
1042
|
+
If you pass an expression to count, it will return the number of records where
|
|
1043
|
+
that expression in not NULL:
|
|
1044
|
+
|
|
1045
|
+
Album.count(:artist_id)
|
|
1046
|
+
# SELECT count(artist_id) AS count FROM albums LIMIT 1
|
|
1047
|
+
# => 1
|
|
1048
|
+
|
|
1026
1049
|
The other methods take a column argument and call the aggregate function with
|
|
1027
1050
|
the argument:
|
|
1028
1051
|
|
|
1029
1052
|
Album.sum(:id)
|
|
1030
|
-
# SELECT sum(id) FROM albums LIMIT 1
|
|
1053
|
+
# SELECT sum(id) AS sum FROM albums LIMIT 1
|
|
1031
1054
|
# => 3
|
|
1032
1055
|
|
|
1033
1056
|
Album.avg(:id)
|
|
1034
|
-
# SELECT avg(id) FROM albums LIMIT 1
|
|
1057
|
+
# SELECT avg(id) AS avg FROM albums LIMIT 1
|
|
1035
1058
|
# => 1.5
|
|
1036
1059
|
|
|
1037
1060
|
Album.min(:id)
|
|
1038
|
-
# SELECT min(id) FROM albums LIMIT 1
|
|
1061
|
+
# SELECT min(id) AS min FROM albums LIMIT 1
|
|
1039
1062
|
# => 1
|
|
1040
1063
|
|
|
1041
1064
|
Album.max(:id)
|
|
1042
|
-
# SELECT max(id) FROM albums LIMIT 1
|
|
1065
|
+
# SELECT max(id) AS max FROM albums LIMIT 1
|
|
1043
1066
|
# => 2
|