sequel 3.21.0 → 3.41.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.
- data/CHANGELOG +1131 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +106 -65
- data/Rakefile +59 -27
- data/bin/sequel +50 -26
- data/doc/active_record.rdoc +68 -52
- data/doc/advanced_associations.rdoc +201 -75
- data/doc/association_basics.rdoc +327 -79
- data/doc/bin_sequel.rdoc +144 -0
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +10 -10
- data/doc/dataset_filtering.rdoc +54 -42
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +89 -557
- data/doc/model_hooks.rdoc +80 -29
- data/doc/object_model.rdoc +576 -0
- data/doc/opening_databases.rdoc +121 -53
- data/doc/prepared_statements.rdoc +41 -15
- data/doc/querying.rdoc +137 -56
- data/doc/reflection.rdoc +36 -10
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/release_notes/3.39.0.txt +237 -0
- data/doc/release_notes/3.40.0.txt +73 -0
- data/doc/release_notes/3.41.0.txt +155 -0
- data/doc/schema_modification.rdoc +585 -0
- data/doc/sharding.rdoc +99 -8
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +169 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +78 -43
- data/lib/sequel/adapters/ado/access.rb +334 -0
- data/lib/sequel/adapters/ado/mssql.rb +18 -12
- data/lib/sequel/adapters/ado.rb +69 -21
- data/lib/sequel/adapters/amalgalite.rb +17 -14
- data/lib/sequel/adapters/cubrid.rb +143 -0
- data/lib/sequel/adapters/db2.rb +178 -85
- data/lib/sequel/adapters/dbi.rb +19 -21
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +2 -61
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +20 -39
- data/lib/sequel/adapters/firebird.rb +33 -210
- data/lib/sequel/adapters/ibmdb.rb +452 -0
- data/lib/sequel/adapters/informix.rb +6 -29
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
- data/lib/sequel/adapters/jdbc/db2.rb +78 -0
- data/lib/sequel/adapters/jdbc/derby.rb +325 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +68 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +72 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +308 -114
- data/lib/sequel/adapters/mock.rb +372 -0
- data/lib/sequel/adapters/mysql.rb +130 -230
- data/lib/sequel/adapters/mysql2.rb +64 -63
- data/lib/sequel/adapters/odbc/mssql.rb +17 -9
- data/lib/sequel/adapters/odbc.rb +29 -10
- data/lib/sequel/adapters/openbase.rb +7 -11
- data/lib/sequel/adapters/oracle.rb +364 -57
- data/lib/sequel/adapters/postgres.rb +379 -145
- data/lib/sequel/adapters/shared/access.rb +236 -11
- data/lib/sequel/adapters/shared/cubrid.rb +216 -0
- data/lib/sequel/adapters/shared/db2.rb +353 -0
- data/lib/sequel/adapters/shared/firebird.rb +231 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +412 -116
- data/lib/sequel/adapters/shared/mysql.rb +396 -89
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
- data/lib/sequel/adapters/shared/oracle.rb +262 -45
- data/lib/sequel/adapters/shared/postgres.rb +688 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +317 -96
- data/lib/sequel/adapters/sqlite.rb +109 -46
- data/lib/sequel/adapters/swift/mysql.rb +10 -12
- data/lib/sequel/adapters/swift/postgres.rb +13 -79
- data/lib/sequel/adapters/swift/sqlite.rb +9 -6
- data/lib/sequel/adapters/swift.rb +31 -27
- data/lib/sequel/adapters/tinytds.rb +177 -25
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
- data/lib/sequel/adapters/utils/pg_types.rb +81 -0
- data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +23 -13
- data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
- data/lib/sequel/connection_pool/single.rb +11 -3
- data/lib/sequel/connection_pool/threaded.rb +69 -20
- data/lib/sequel/connection_pool.rb +20 -18
- data/lib/sequel/core.rb +143 -11
- data/lib/sequel/database/connecting.rb +66 -29
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +192 -51
- data/lib/sequel/database/query.rb +299 -114
- data/lib/sequel/database/schema_generator.rb +103 -36
- data/lib/sequel/database/schema_methods.rb +310 -69
- data/lib/sequel/dataset/actions.rb +344 -90
- data/lib/sequel/dataset/features.rb +101 -8
- data/lib/sequel/dataset/graph.rb +42 -15
- data/lib/sequel/dataset/misc.rb +52 -25
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +322 -68
- data/lib/sequel/dataset/sql.rb +716 -293
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +83 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +72 -0
- data/lib/sequel/extensions/connection_validator.rb +109 -0
- data/lib/sequel/extensions/constraint_validations.rb +451 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
- data/lib/sequel/extensions/eval_inspect.rb +173 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +100 -11
- data/lib/sequel/extensions/named_timezones.rb +9 -0
- data/lib/sequel/extensions/null_dataset.rb +94 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +539 -0
- data/lib/sequel/extensions/pg_array_ops.rb +263 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
- data/lib/sequel/extensions/pg_hstore.rb +334 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
- data/lib/sequel/extensions/pg_inet.rb +113 -0
- data/lib/sequel/extensions/pg_interval.rb +191 -0
- data/lib/sequel/extensions/pg_json.rb +212 -0
- data/lib/sequel/extensions/pg_range.rb +513 -0
- data/lib/sequel/extensions/pg_range_ops.rb +150 -0
- data/lib/sequel/extensions/pg_row.rb +576 -0
- data/lib/sequel/extensions/pg_row_ops.rb +182 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
- data/lib/sequel/extensions/pretty_table.rb +17 -72
- data/lib/sequel/extensions/query.rb +8 -4
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +282 -76
- data/lib/sequel/extensions/select_remove.rb +39 -0
- data/lib/sequel/extensions/server_block.rb +140 -0
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +8 -110
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
- data/lib/sequel/extensions/to_dot.rb +99 -83
- data/lib/sequel/model/associations.rb +1263 -409
- data/lib/sequel/model/base.rb +624 -171
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +24 -2
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +137 -16
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/constraint_validations.rb +198 -0
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +72 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +134 -15
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +77 -6
- data/lib/sequel/plugins/list.rb +13 -2
- data/lib/sequel/plugins/many_through_many.rb +103 -51
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +150 -66
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/prepared_statements.rb +168 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +31 -17
- data/lib/sequel/plugins/schema.rb +8 -3
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +57 -12
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +29 -3
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +18 -6
- data/lib/sequel/plugins/tree.rb +3 -3
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +57 -4
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +721 -141
- data/lib/sequel/timezones.rb +67 -40
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +53 -39
- data/spec/adapters/mssql_spec.rb +261 -66
- data/spec/adapters/mysql_spec.rb +597 -352
- data/spec/adapters/oracle_spec.rb +92 -117
- data/spec/adapters/postgres_spec.rb +2103 -341
- data/spec/adapters/spec_helper.rb +16 -6
- data/spec/adapters/sqlite_spec.rb +237 -76
- data/spec/core/connection_pool_spec.rb +270 -141
- data/spec/core/database_spec.rb +980 -524
- data/spec/core/dataset_spec.rb +1658 -1243
- data/spec/core/expression_filters_spec.rb +741 -334
- data/spec/core/mock_adapter_spec.rb +453 -0
- data/spec/core/object_graph_spec.rb +88 -129
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +556 -53
- data/spec/core/spec_helper.rb +7 -48
- data/spec/core_extensions_spec.rb +626 -0
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +227 -33
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/caching_spec.rb +47 -51
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/connection_validator_spec.rb +118 -0
- data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
- data/spec/extensions/constraint_validations_spec.rb +316 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +88 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/eval_inspect_spec.rb +67 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +97 -128
- data/spec/extensions/identity_map_spec.rb +142 -24
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -12
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +49 -40
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +368 -254
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +268 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +112 -0
- data/spec/extensions/pg_array_spec.rb +324 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
- data/spec/extensions/pg_hstore_spec.rb +200 -0
- data/spec/extensions/pg_inet_spec.rb +47 -0
- data/spec/extensions/pg_interval_spec.rb +72 -0
- data/spec/extensions/pg_json_spec.rb +99 -0
- data/spec/extensions/pg_range_ops_spec.rb +56 -0
- data/spec/extensions/pg_range_spec.rb +395 -0
- data/spec/extensions/pg_row_ops_spec.rb +58 -0
- data/spec/extensions/pg_row_plugin_spec.rb +49 -0
- data/spec/extensions/pg_row_spec.rb +340 -0
- data/spec/extensions/pg_statement_cache_spec.rb +208 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +167 -0
- data/spec/extensions/query_spec.rb +9 -3
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +434 -49
- data/spec/extensions/schema_spec.rb +30 -49
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +86 -48
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +65 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +34 -67
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/subclasses_spec.rb +14 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +8 -11
- data/spec/extensions/touch_spec.rb +53 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +9 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +77 -68
- data/spec/extensions/validation_helpers_spec.rb +48 -37
- data/spec/extensions/xml_serializer_spec.rb +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +25 -5
- data/spec/integration/dataset_test.rb +729 -141
- data/spec/integration/eager_loader_test.rb +38 -54
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +871 -160
- data/spec/integration/prepared_statement_test.rb +272 -128
- data/spec/integration/schema_test.rb +377 -57
- data/spec/integration/spec_helper.rb +49 -32
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +40 -8
- data/spec/model/association_reflection_spec.rb +207 -8
- data/spec/model/associations_spec.rb +1206 -693
- data/spec/model/base_spec.rb +334 -100
- data/spec/model/dataset_methods_spec.rb +45 -27
- data/spec/model/eager_loading_spec.rb +828 -692
- data/spec/model/hooks_spec.rb +355 -67
- data/spec/model/model_spec.rb +251 -179
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +506 -232
- data/spec/model/spec_helper.rb +16 -77
- data/spec/model/validations_spec.rb +38 -2
- data/spec/rcov.opts +2 -0
- metadata +223 -81
- data/spec/core/core_sql_spec.rb +0 -451
data/lib/sequel/dataset/query.rb
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
# ---------------------
|
|
4
|
-
# :section: Methods that return modified datasets
|
|
4
|
+
# :section: 1 - Methods that return modified datasets
|
|
5
5
|
# These methods all return modified copies of the receiver.
|
|
6
6
|
# ---------------------
|
|
7
7
|
|
|
8
|
+
# Hash of extension name symbols to callable objects to load the extension
|
|
9
|
+
# into the Dataset object (usually by extending it with a module defined
|
|
10
|
+
# in the extension).
|
|
11
|
+
EXTENSIONS = {}
|
|
12
|
+
|
|
8
13
|
# The dataset options that require the removal of cached columns
|
|
9
14
|
# if changed.
|
|
10
15
|
COLUMN_CHANGE_OPTS = [:select, :sql, :from, :join].freeze
|
|
@@ -28,12 +33,35 @@ module Sequel
|
|
|
28
33
|
JOIN_METHODS = (CONDITIONED_JOIN_TYPES + UNCONDITIONED_JOIN_TYPES).map{|x| "#{x}_join".to_sym} + [:join, :join_table]
|
|
29
34
|
|
|
30
35
|
# Methods that return modified datasets
|
|
31
|
-
QUERY_METHODS =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
QUERY_METHODS = (<<-METHS).split.map{|x| x.to_sym} + JOIN_METHODS
|
|
37
|
+
add_graph_aliases and distinct except exclude exclude_having exclude_where
|
|
38
|
+
filter for_update from from_self graph grep group group_and_count group_by having intersect invert
|
|
39
|
+
limit lock_style naked or order order_append order_by order_more order_prepend paginate qualify query
|
|
40
|
+
reverse reverse_order select select_all select_append select_group select_more server
|
|
41
|
+
set_defaults set_graph_aliases set_overrides unfiltered ungraphed ungrouped union
|
|
42
|
+
unlimited unordered where with with_recursive with_sql
|
|
43
|
+
METHS
|
|
44
|
+
|
|
45
|
+
# Register an extension callback for Dataset objects. ext should be the
|
|
46
|
+
# extension name symbol, and mod should either be a Module that the
|
|
47
|
+
# dataset is extended with, or a callable object called with the database
|
|
48
|
+
# object. If mod is not provided, a block can be provided and is treated
|
|
49
|
+
# as the mod object.
|
|
50
|
+
#
|
|
51
|
+
# If mod is a module, this also registers a Database extension that will
|
|
52
|
+
# extend all of the database's datasets.
|
|
53
|
+
def self.register_extension(ext, mod=nil, &block)
|
|
54
|
+
if mod
|
|
55
|
+
raise(Error, "cannot provide both mod and block to Dataset.register_extension") if block
|
|
56
|
+
if mod.is_a?(Module)
|
|
57
|
+
block = proc{|ds| ds.extend(mod)}
|
|
58
|
+
Sequel::Database.register_extension(ext){|db| db.extend_datasets(mod)}
|
|
59
|
+
else
|
|
60
|
+
block = mod
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
Sequel.synchronize{EXTENSIONS[ext] = block}
|
|
64
|
+
end
|
|
37
65
|
|
|
38
66
|
# Adds an further filter to an existing filter using AND. If no filter
|
|
39
67
|
# exists an error is raised. This method is identical to #filter except
|
|
@@ -80,7 +108,7 @@ module Sequel
|
|
|
80
108
|
# :from_self :: Set to false to not wrap the returned dataset in a from_self, use with care.
|
|
81
109
|
#
|
|
82
110
|
# DB[:items].except(DB[:other_items])
|
|
83
|
-
# # SELECT * FROM items EXCEPT SELECT * FROM other_items
|
|
111
|
+
# # SELECT * FROM (SELECT * FROM items EXCEPT SELECT * FROM other_items) AS t1
|
|
84
112
|
#
|
|
85
113
|
# DB[:items].except(DB[:other_items], :all=>true, :from_self=>false)
|
|
86
114
|
# # SELECT * FROM items EXCEPT ALL SELECT * FROM other_items
|
|
@@ -103,12 +131,51 @@ module Sequel
|
|
|
103
131
|
# DB[:items].exclude(:category => 'software', :id=>3)
|
|
104
132
|
# # SELECT * FROM items WHERE ((category != 'software') OR (id != 3))
|
|
105
133
|
def exclude(*cond, &block)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
134
|
+
_filter_or_exclude(true, @opts[:having] ? :having : :where, *cond, &block)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Inverts the given conditions and adds them to the HAVING clause.
|
|
138
|
+
#
|
|
139
|
+
# DB[:items].select_group(:name).exclude_having{count(name) < 2}
|
|
140
|
+
# # SELECT name FROM items GROUP BY name HAVING (count(name) >= 2)
|
|
141
|
+
def exclude_having(*cond, &block)
|
|
142
|
+
_filter_or_exclude(true, :having, *cond, &block)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Inverts the given conditions and adds them to the WHERE clause.
|
|
146
|
+
#
|
|
147
|
+
# DB[:items].select_group(:name).exclude_where(:category => 'software')
|
|
148
|
+
# # SELECT * FROM items WHERE (category != 'software')
|
|
149
|
+
#
|
|
150
|
+
# DB[:items].select_group(:name).
|
|
151
|
+
# exclude_having{count(name) < 2}.
|
|
152
|
+
# exclude_where(:category => 'software')
|
|
153
|
+
# # SELECT name FROM items WHERE (category != 'software')
|
|
154
|
+
# # GROUP BY name HAVING (count(name) >= 2)
|
|
155
|
+
def exclude_where(*cond, &block)
|
|
156
|
+
_filter_or_exclude(true, :where, *cond, &block)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Return a clone of the dataset loaded with the extensions, see #extension!.
|
|
160
|
+
def extension(*exts)
|
|
161
|
+
clone.extension!(*exts)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Load an extension into the receiver. In addition to requiring the extension file, this
|
|
165
|
+
# also modifies the dataset to work with the extension (usually extending it with a
|
|
166
|
+
# module defined in the extension file). If no related extension file exists or the
|
|
167
|
+
# extension does not have specific support for Database objects, an Error will be raised.
|
|
168
|
+
# Returns self.
|
|
169
|
+
def extension!(*exts)
|
|
170
|
+
Sequel.extension(*exts)
|
|
171
|
+
exts.each do |ext|
|
|
172
|
+
if pr = Sequel.synchronize{EXTENSIONS[ext]}
|
|
173
|
+
pr.call(self)
|
|
174
|
+
else
|
|
175
|
+
raise(Error, "Extension #{ext} does not have specific support handling individual datasets")
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
self
|
|
112
179
|
end
|
|
113
180
|
|
|
114
181
|
# Returns a copy of the dataset with the given conditions imposed upon it.
|
|
@@ -145,7 +212,7 @@ module Sequel
|
|
|
145
212
|
# DB[:items].filter('price < ?', 100)
|
|
146
213
|
# # SELECT * FROM items WHERE price < 100
|
|
147
214
|
#
|
|
148
|
-
# DB[:items].filter([[:id,
|
|
215
|
+
# DB[:items].filter([[:id, [1,2,3]], [:id, 0..10]])
|
|
149
216
|
# # SELECT * FROM items WHERE ((id IN (1, 2, 3)) AND ((id >= 0) AND (id <= 10)))
|
|
150
217
|
#
|
|
151
218
|
# DB[:items].filter('price < 100')
|
|
@@ -184,16 +251,22 @@ module Sequel
|
|
|
184
251
|
def from(*source)
|
|
185
252
|
table_alias_num = 0
|
|
186
253
|
sources = []
|
|
254
|
+
ctes = nil
|
|
187
255
|
source.each do |s|
|
|
188
256
|
case s
|
|
189
257
|
when Hash
|
|
190
258
|
s.each{|k,v| sources << SQL::AliasedExpression.new(k,v)}
|
|
191
259
|
when Dataset
|
|
260
|
+
if hoist_cte?(s)
|
|
261
|
+
ctes ||= []
|
|
262
|
+
ctes += s.opts[:with]
|
|
263
|
+
s = s.clone(:with=>nil)
|
|
264
|
+
end
|
|
192
265
|
sources << SQL::AliasedExpression.new(s, dataset_alias(table_alias_num+=1))
|
|
193
266
|
when Symbol
|
|
194
267
|
sch, table, aliaz = split_symbol(s)
|
|
195
268
|
if aliaz
|
|
196
|
-
s = sch ? SQL::QualifiedIdentifier.new(sch
|
|
269
|
+
s = sch ? SQL::QualifiedIdentifier.new(sch, table) : SQL::Identifier.new(table)
|
|
197
270
|
sources << SQL::AliasedExpression.new(s, aliaz.to_sym)
|
|
198
271
|
else
|
|
199
272
|
sources << s
|
|
@@ -203,6 +276,7 @@ module Sequel
|
|
|
203
276
|
end
|
|
204
277
|
end
|
|
205
278
|
o = {:from=>sources.empty? ? nil : sources}
|
|
279
|
+
o[:with] = (opts[:with] || []) + ctes if ctes
|
|
206
280
|
o[:num_dataset_sources] = table_alias_num if table_alias_num > 0
|
|
207
281
|
clone(o)
|
|
208
282
|
end
|
|
@@ -270,21 +344,25 @@ module Sequel
|
|
|
270
344
|
end
|
|
271
345
|
|
|
272
346
|
# Returns a copy of the dataset with the results grouped by the value of
|
|
273
|
-
# the given columns.
|
|
347
|
+
# the given columns. If a block is given, it is treated
|
|
348
|
+
# as a virtual row block, similar to +filter+.
|
|
274
349
|
#
|
|
275
350
|
# DB[:items].group(:id) # SELECT * FROM items GROUP BY id
|
|
276
351
|
# DB[:items].group(:id, :name) # SELECT * FROM items GROUP BY id, name
|
|
277
|
-
|
|
352
|
+
# DB[:items].group{[a, sum(b)]} # SELECT * FROM items GROUP BY a, sum(b)
|
|
353
|
+
def group(*columns, &block)
|
|
354
|
+
virtual_row_columns(columns, block)
|
|
278
355
|
clone(:group => (columns.compact.empty? ? nil : columns))
|
|
279
356
|
end
|
|
280
357
|
|
|
281
358
|
# Alias of group
|
|
282
|
-
def group_by(*columns)
|
|
283
|
-
group(*columns)
|
|
359
|
+
def group_by(*columns, &block)
|
|
360
|
+
group(*columns, &block)
|
|
284
361
|
end
|
|
285
362
|
|
|
286
363
|
# Returns a dataset grouped by the given column with count by group.
|
|
287
364
|
# Column aliases may be supplied, and will be included in the select clause.
|
|
365
|
+
# If a block is given, it is treated as a virtual row block, similar to +filter+.
|
|
288
366
|
#
|
|
289
367
|
# Examples:
|
|
290
368
|
#
|
|
@@ -299,8 +377,24 @@ module Sequel
|
|
|
299
377
|
# DB[:items].group_and_count(:first_name___name).all
|
|
300
378
|
# # SELECT first_name AS name, count(*) AS count FROM items GROUP BY first_name
|
|
301
379
|
# # => [{:name=>'a', :count=>1}, ...]
|
|
302
|
-
|
|
303
|
-
|
|
380
|
+
#
|
|
381
|
+
# DB[:items].group_and_count{substr(first_name, 1, 1).as(initial)}.all
|
|
382
|
+
# # SELECT substr(first_name, 1, 1) AS initial, count(*) AS count FROM items GROUP BY substr(first_name, 1, 1)
|
|
383
|
+
# # => [{:initial=>'a', :count=>1}, ...]
|
|
384
|
+
def group_and_count(*columns, &block)
|
|
385
|
+
select_group(*columns, &block).select_more(COUNT_OF_ALL_AS_COUNT)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Adds the appropriate CUBE syntax to GROUP BY.
|
|
389
|
+
def group_cube
|
|
390
|
+
raise Error, "GROUP BY CUBE not supported on #{db.database_type}" unless supports_group_cube?
|
|
391
|
+
clone(:group_options=>:cube)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# Adds the appropriate ROLLUP syntax to GROUP BY.
|
|
395
|
+
def group_rollup
|
|
396
|
+
raise Error, "GROUP BY ROLLUP not supported on #{db.database_type}" unless supports_group_rollup?
|
|
397
|
+
clone(:group_options=>:rollup)
|
|
304
398
|
end
|
|
305
399
|
|
|
306
400
|
# Returns a copy of the dataset with the HAVING conditions changed. See #filter for argument types.
|
|
@@ -356,12 +450,15 @@ module Sequel
|
|
|
356
450
|
inner_join(*args, &block)
|
|
357
451
|
end
|
|
358
452
|
|
|
359
|
-
# Returns a joined dataset.
|
|
453
|
+
# Returns a joined dataset. Not usually called directly, users should use the
|
|
454
|
+
# appropriate join method (e.g. join, left_join, natural_join, cross_join) which fills
|
|
455
|
+
# in the +type+ argument.
|
|
456
|
+
#
|
|
457
|
+
# Takes the following arguments:
|
|
360
458
|
#
|
|
361
459
|
# * type - The type of join to do (e.g. :inner)
|
|
362
460
|
# * table - Depends on type:
|
|
363
461
|
# * Dataset - a subselect is performed with an alias of tN for some value of N
|
|
364
|
-
# * Model (or anything responding to :table_name) - table.table_name
|
|
365
462
|
# * String, Symbol: table
|
|
366
463
|
# * expr - specifies conditions, depends on type:
|
|
367
464
|
# * Hash, Array of two element arrays - Assumes key (1st arg) is column of joined table (unless already
|
|
@@ -382,11 +479,36 @@ module Sequel
|
|
|
382
479
|
# to the same table more than once. No alias is used by default.
|
|
383
480
|
# * :implicit_qualifier - The name to use for qualifying implicit conditions. By default,
|
|
384
481
|
# the last joined or primary table is used.
|
|
482
|
+
# * :qualify - Can be set to false to not do any implicit qualification. Can be set
|
|
483
|
+
# to :deep to use the Qualifier AST Transformer, which will attempt to qualify
|
|
484
|
+
# subexpressions of the expression tree.
|
|
385
485
|
# * block - The block argument should only be given if a JOIN with an ON clause is used,
|
|
386
486
|
# in which case it yields the table alias/name for the table currently being joined,
|
|
387
487
|
# the table alias/name for the last joined (or first table), and an array of previous
|
|
388
488
|
# SQL::JoinClause. Unlike +filter+, this block is not treated as a virtual row block.
|
|
489
|
+
#
|
|
490
|
+
# Examples:
|
|
491
|
+
#
|
|
492
|
+
# DB[:a].join_table(:cross, :b)
|
|
493
|
+
# # SELECT * FROM a CROSS JOIN b
|
|
494
|
+
#
|
|
495
|
+
# DB[:a].join_table(:inner, DB[:b], :c=>d)
|
|
496
|
+
# # SELECT * FROM a INNER JOIN (SELECT * FROM b) AS t1 ON (t1.c = a.d)
|
|
497
|
+
#
|
|
498
|
+
# DB[:a].join_table(:left, :b___c, [:d])
|
|
499
|
+
# # SELECT * FROM a LEFT JOIN b AS c USING (d)
|
|
500
|
+
#
|
|
501
|
+
# DB[:a].natural_join(:b).join_table(:inner, :c) do |ta, jta, js|
|
|
502
|
+
# (Sequel.qualify(ta, :d) > Sequel.qualify(jta, :e)) & {Sequel.qualify(ta, :f)=>DB.from(js.first.table).select(:g)}
|
|
503
|
+
# end
|
|
504
|
+
# # SELECT * FROM a NATURAL JOIN b INNER JOIN c
|
|
505
|
+
# # ON ((c.d > b.e) AND (c.f IN (SELECT g FROM b)))
|
|
389
506
|
def join_table(type, table, expr=nil, options={}, &block)
|
|
507
|
+
if hoist_cte?(table)
|
|
508
|
+
s, ds = hoist_cte(table)
|
|
509
|
+
return s.join_table(type, ds, expr, options, &block)
|
|
510
|
+
end
|
|
511
|
+
|
|
390
512
|
using_join = expr.is_a?(Array) && !expr.empty? && expr.all?{|x| x.is_a?(Symbol)}
|
|
391
513
|
if using_join && !supports_join_using?
|
|
392
514
|
h = {}
|
|
@@ -398,6 +520,7 @@ module Sequel
|
|
|
398
520
|
when Hash
|
|
399
521
|
table_alias = options[:table_alias]
|
|
400
522
|
last_alias = options[:implicit_qualifier]
|
|
523
|
+
qualify_type = options[:qualify]
|
|
401
524
|
when Symbol, String, SQL::Identifier
|
|
402
525
|
table_alias = options
|
|
403
526
|
last_alias = nil
|
|
@@ -412,7 +535,6 @@ module Sequel
|
|
|
412
535
|
end
|
|
413
536
|
table_name = table_alias
|
|
414
537
|
else
|
|
415
|
-
table = table.table_name if table.respond_to?(:table_name)
|
|
416
538
|
table, implicit_table_alias = split_alias(table)
|
|
417
539
|
table_alias ||= implicit_table_alias
|
|
418
540
|
table_name = table_alias || table
|
|
@@ -427,10 +549,19 @@ module Sequel
|
|
|
427
549
|
last_alias ||= @opts[:last_joined_table] || first_source_alias
|
|
428
550
|
if Sequel.condition_specifier?(expr)
|
|
429
551
|
expr = expr.collect do |k, v|
|
|
430
|
-
|
|
431
|
-
|
|
552
|
+
case qualify_type
|
|
553
|
+
when false
|
|
554
|
+
nil # Do no qualification
|
|
555
|
+
when :deep
|
|
556
|
+
k = Sequel::Qualifier.new(self, table_name).transform(k)
|
|
557
|
+
v = Sequel::Qualifier.new(self, last_alias).transform(v)
|
|
558
|
+
else
|
|
559
|
+
k = qualified_column_name(k, table_name) if k.is_a?(Symbol)
|
|
560
|
+
v = qualified_column_name(v, last_alias) if v.is_a?(Symbol)
|
|
561
|
+
end
|
|
432
562
|
[k,v]
|
|
433
563
|
end
|
|
564
|
+
expr = SQL::BooleanExpression.from_value_pairs(expr)
|
|
434
565
|
end
|
|
435
566
|
if block
|
|
436
567
|
expr2 = yield(table_name, last_alias, @opts[:join] || [])
|
|
@@ -461,7 +592,7 @@ module Sequel
|
|
|
461
592
|
# DB[:items].limit(10...20) # SELECT * FROM items LIMIT 10 OFFSET 10
|
|
462
593
|
# DB[:items].limit(10..20) # SELECT * FROM items LIMIT 11 OFFSET 10
|
|
463
594
|
# DB[:items].limit(nil, 20) # SELECT * FROM items OFFSET 20
|
|
464
|
-
def limit(l, o = nil)
|
|
595
|
+
def limit(l, o = (no_offset = true; nil))
|
|
465
596
|
return from_self.limit(l, o) if @opts[:sql]
|
|
466
597
|
|
|
467
598
|
if Range === l
|
|
@@ -479,6 +610,8 @@ module Sequel
|
|
|
479
610
|
raise(Error, 'Offsets must be greater than or equal to 0') unless o >= 0
|
|
480
611
|
end
|
|
481
612
|
opts[:offset] = o
|
|
613
|
+
elsif !no_offset
|
|
614
|
+
opts[:offset] = nil
|
|
482
615
|
end
|
|
483
616
|
clone(opts)
|
|
484
617
|
end
|
|
@@ -524,14 +657,14 @@ module Sequel
|
|
|
524
657
|
#
|
|
525
658
|
# DB[:items].order(:name) # SELECT * FROM items ORDER BY name
|
|
526
659
|
# DB[:items].order(:a, :b) # SELECT * FROM items ORDER BY a, b
|
|
527
|
-
# DB[:items].order('a + b'
|
|
660
|
+
# DB[:items].order(Sequel.lit('a + b')) # SELECT * FROM items ORDER BY a + b
|
|
528
661
|
# DB[:items].order(:a + :b) # SELECT * FROM items ORDER BY (a + b)
|
|
529
|
-
# DB[:items].order(:name
|
|
530
|
-
# DB[:items].order(
|
|
662
|
+
# DB[:items].order(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name DESC
|
|
663
|
+
# DB[:items].order(Sequel.asc(:name, :nulls=>:last)) # SELECT * FROM items ORDER BY name ASC NULLS LAST
|
|
531
664
|
# DB[:items].order{sum(name).desc} # SELECT * FROM items ORDER BY sum(name) DESC
|
|
532
665
|
# DB[:items].order(nil) # SELECT * FROM items
|
|
533
666
|
def order(*columns, &block)
|
|
534
|
-
columns
|
|
667
|
+
virtual_row_columns(columns, block)
|
|
535
668
|
clone(:order => (columns.compact.empty?) ? nil : columns)
|
|
536
669
|
end
|
|
537
670
|
|
|
@@ -565,7 +698,7 @@ module Sequel
|
|
|
565
698
|
@opts[:order] ? ds.order_more(*@opts[:order]) : ds
|
|
566
699
|
end
|
|
567
700
|
|
|
568
|
-
# Qualify to the given table, or first source if
|
|
701
|
+
# Qualify to the given table, or first source if no table is given.
|
|
569
702
|
#
|
|
570
703
|
# DB[:items].filter(:id=>1).qualify
|
|
571
704
|
# # SELECT items.* FROM items WHERE (items.id = 1)
|
|
@@ -606,19 +739,33 @@ module Sequel
|
|
|
606
739
|
qualify_to(first_source)
|
|
607
740
|
end
|
|
608
741
|
|
|
742
|
+
# Modify the RETURNING clause, only supported on a few databases. If returning
|
|
743
|
+
# is used, instead of insert returning the autogenerated primary key or
|
|
744
|
+
# update/delete returning the number of modified rows, results are
|
|
745
|
+
# returned using +fetch_rows+.
|
|
746
|
+
#
|
|
747
|
+
# DB[:items].returning # RETURNING *
|
|
748
|
+
# DB[:items].returning(nil) # RETURNING NULL
|
|
749
|
+
# DB[:items].returning(:id, :name) # RETURNING id, name
|
|
750
|
+
def returning(*values)
|
|
751
|
+
clone(:returning=>values)
|
|
752
|
+
end
|
|
753
|
+
|
|
609
754
|
# Returns a copy of the dataset with the order reversed. If no order is
|
|
610
755
|
# given, the existing order is inverted.
|
|
611
756
|
#
|
|
612
757
|
# DB[:items].reverse(:id) # SELECT * FROM items ORDER BY id DESC
|
|
758
|
+
# DB[:items].reverse{foo(bar)} # SELECT * FROM items ORDER BY foo(bar) DESC
|
|
613
759
|
# DB[:items].order(:id).reverse # SELECT * FROM items ORDER BY id DESC
|
|
614
|
-
# DB[:items].order(:id).reverse(:name
|
|
615
|
-
def reverse(*order)
|
|
760
|
+
# DB[:items].order(:id).reverse(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name ASC
|
|
761
|
+
def reverse(*order, &block)
|
|
762
|
+
virtual_row_columns(order, block)
|
|
616
763
|
order(*invert_order(order.empty? ? @opts[:order] : order))
|
|
617
764
|
end
|
|
618
765
|
|
|
619
766
|
# Alias of +reverse+
|
|
620
|
-
def reverse_order(*order)
|
|
621
|
-
reverse(*order)
|
|
767
|
+
def reverse_order(*order, &block)
|
|
768
|
+
reverse(*order, &block)
|
|
622
769
|
end
|
|
623
770
|
|
|
624
771
|
# Returns a copy of the dataset with the columns selected changed
|
|
@@ -629,7 +776,7 @@ module Sequel
|
|
|
629
776
|
# DB[:items].select(:a, :b) # SELECT a, b FROM items
|
|
630
777
|
# DB[:items].select{[a, sum(b)]} # SELECT a, sum(b) FROM items
|
|
631
778
|
def select(*columns, &block)
|
|
632
|
-
columns
|
|
779
|
+
virtual_row_columns(columns, block)
|
|
633
780
|
m = []
|
|
634
781
|
columns.each do |i|
|
|
635
782
|
i.is_a?(Hash) ? m.concat(i.map{|k, v| SQL::AliasedExpression.new(k,v)}) : m << i
|
|
@@ -637,11 +784,19 @@ module Sequel
|
|
|
637
784
|
clone(:select => m)
|
|
638
785
|
end
|
|
639
786
|
|
|
640
|
-
# Returns a copy of the dataset selecting the wildcard
|
|
787
|
+
# Returns a copy of the dataset selecting the wildcard if no arguments
|
|
788
|
+
# are given. If arguments are given, treat them as tables and select
|
|
789
|
+
# all columns (using the wildcard) from each table.
|
|
641
790
|
#
|
|
642
791
|
# DB[:items].select(:a).select_all # SELECT * FROM items
|
|
643
|
-
|
|
644
|
-
|
|
792
|
+
# DB[:items].select_all(:items) # SELECT items.* FROM items
|
|
793
|
+
# DB[:items].select_all(:items, :foo) # SELECT items.*, foo.* FROM items
|
|
794
|
+
def select_all(*tables)
|
|
795
|
+
if tables.empty?
|
|
796
|
+
clone(:select => nil)
|
|
797
|
+
else
|
|
798
|
+
select(*tables.map{|t| i, a = split_alias(t); a || i}.map{|t| SQL::ColumnAll.new(t)})
|
|
799
|
+
end
|
|
645
800
|
end
|
|
646
801
|
|
|
647
802
|
# Returns a copy of the dataset with the given columns added
|
|
@@ -653,10 +808,29 @@ module Sequel
|
|
|
653
808
|
# DB[:items].select_append(:b) # SELECT *, b FROM items
|
|
654
809
|
def select_append(*columns, &block)
|
|
655
810
|
cur_sel = @opts[:select]
|
|
656
|
-
|
|
811
|
+
if !cur_sel || cur_sel.empty?
|
|
812
|
+
unless supports_select_all_and_column?
|
|
813
|
+
return select_all(*(Array(@opts[:from]) + Array(@opts[:join]))).select_more(*columns, &block)
|
|
814
|
+
end
|
|
815
|
+
cur_sel = [WILDCARD]
|
|
816
|
+
end
|
|
657
817
|
select(*(cur_sel + columns), &block)
|
|
658
818
|
end
|
|
659
819
|
|
|
820
|
+
# Set both the select and group clauses with the given +columns+.
|
|
821
|
+
# Column aliases may be supplied, and will be included in the select clause.
|
|
822
|
+
# This also takes a virtual row block similar to +filter+.
|
|
823
|
+
#
|
|
824
|
+
# DB[:items].select_group(:a, :b)
|
|
825
|
+
# # SELECT a, b FROM items GROUP BY a, b
|
|
826
|
+
#
|
|
827
|
+
# DB[:items].select_group(:c___a){f(c2)}
|
|
828
|
+
# # SELECT c AS a, f(c2) FROM items GROUP BY c, f(c2)
|
|
829
|
+
def select_group(*columns, &block)
|
|
830
|
+
virtual_row_columns(columns, block)
|
|
831
|
+
select(*columns).group(*columns.map{|c| unaliased_identifier(c)})
|
|
832
|
+
end
|
|
833
|
+
|
|
660
834
|
# Returns a copy of the dataset with the given columns added
|
|
661
835
|
# to the existing selected columns. If no columns are currently selected
|
|
662
836
|
# it will just select the columns given.
|
|
@@ -670,7 +844,7 @@ module Sequel
|
|
|
670
844
|
end
|
|
671
845
|
|
|
672
846
|
# Set the server for this dataset to use. Used to pick a specific database
|
|
673
|
-
# shard to run a query against, or to override the default (
|
|
847
|
+
# shard to run a query against, or to override the default (where SELECT uses
|
|
674
848
|
# :read_only database and all other queries use the :default database). This
|
|
675
849
|
# method is always available but is only useful when database sharding is being
|
|
676
850
|
# used.
|
|
@@ -702,6 +876,22 @@ module Sequel
|
|
|
702
876
|
clone(:overrides=>hash.merge(@opts[:overrides]||{}))
|
|
703
877
|
end
|
|
704
878
|
|
|
879
|
+
# Unbind bound variables from this dataset's filter and return an array of two
|
|
880
|
+
# objects. The first object is a modified dataset where the filter has been
|
|
881
|
+
# replaced with one that uses bound variable placeholders. The second object
|
|
882
|
+
# is the hash of unbound variables. You can then prepare and execute (or just
|
|
883
|
+
# call) the dataset with the bound variables to get results.
|
|
884
|
+
#
|
|
885
|
+
# ds, bv = DB[:items].filter(:a=>1).unbind
|
|
886
|
+
# ds # SELECT * FROM items WHERE (a = $a)
|
|
887
|
+
# bv # {:a => 1}
|
|
888
|
+
# ds.call(:select, bv)
|
|
889
|
+
def unbind
|
|
890
|
+
u = Unbinder.new
|
|
891
|
+
ds = clone(:where=>u.transform(opts[:where]), :join=>u.transform(opts[:join]))
|
|
892
|
+
[ds, u.binds]
|
|
893
|
+
end
|
|
894
|
+
|
|
705
895
|
# Returns a copy of the dataset with no filters (HAVING or WHERE clause) applied.
|
|
706
896
|
#
|
|
707
897
|
# DB[:items].group(:a).having(:a=>1).where(:b).unfiltered
|
|
@@ -726,8 +916,8 @@ module Sequel
|
|
|
726
916
|
# :all :: Set to true to use UNION ALL instead of UNION, so duplicate rows can occur
|
|
727
917
|
# :from_self :: Set to false to not wrap the returned dataset in a from_self, use with care.
|
|
728
918
|
#
|
|
729
|
-
# DB[:items].union(DB[:other_items])
|
|
730
|
-
#
|
|
919
|
+
# DB[:items].union(DB[:other_items])
|
|
920
|
+
# # SELECT * FROM (SELECT * FROM items UNION SELECT * FROM other_items) AS t1
|
|
731
921
|
#
|
|
732
922
|
# DB[:items].union(DB[:other_items], :all=>true, :from_self=>false)
|
|
733
923
|
# # SELECT * FROM items UNION ALL SELECT * FROM other_items
|
|
@@ -774,7 +964,12 @@ module Sequel
|
|
|
774
964
|
# # WITH items AS (SELECT * FROM syx WHERE (name LIKE 'A%')) SELECT * FROM items
|
|
775
965
|
def with(name, dataset, opts={})
|
|
776
966
|
raise(Error, 'This datatset does not support common table expressions') unless supports_cte?
|
|
777
|
-
|
|
967
|
+
if hoist_cte?(dataset)
|
|
968
|
+
s, ds = hoist_cte(dataset)
|
|
969
|
+
s.with(name, ds, opts)
|
|
970
|
+
else
|
|
971
|
+
clone(:with=>(@opts[:with]||[]) + [opts.merge(:name=>name, :dataset=>dataset)])
|
|
972
|
+
end
|
|
778
973
|
end
|
|
779
974
|
|
|
780
975
|
# Add a recursive common table expression (CTE) with the given name, a dataset that
|
|
@@ -783,33 +978,62 @@ module Sequel
|
|
|
783
978
|
# :args :: Specify the arguments/columns for the CTE, should be an array of symbols.
|
|
784
979
|
# :union_all :: Set to false to use UNION instead of UNION ALL combining the nonrecursive and recursive parts.
|
|
785
980
|
#
|
|
786
|
-
# DB[:t].
|
|
787
|
-
#
|
|
788
|
-
#
|
|
789
|
-
#
|
|
790
|
-
#
|
|
791
|
-
# # WITH RECURSIVE t(
|
|
792
|
-
# # SELECT
|
|
981
|
+
# DB[:t].with_recursive(:t,
|
|
982
|
+
# DB[:i1].select(:id, :parent_id).filter(:parent_id=>nil),
|
|
983
|
+
# DB[:i1].join(:t, :id=>:parent_id).select(:i1__id, :i1__parent_id),
|
|
984
|
+
# :args=>[:id, :parent_id])
|
|
985
|
+
#
|
|
986
|
+
# # WITH RECURSIVE "t"("id", "parent_id") AS (
|
|
987
|
+
# # SELECT "id", "parent_id" FROM "i1" WHERE ("parent_id" IS NULL)
|
|
793
988
|
# # UNION ALL
|
|
794
|
-
# # SELECT i1.id, i1.parent_id FROM
|
|
795
|
-
# # )
|
|
796
|
-
# # SELECT i AS id, pi AS parent_id FROM t
|
|
989
|
+
# # SELECT "i1"."id", "i1"."parent_id" FROM "i1" INNER JOIN "t" ON ("t"."id" = "i1"."parent_id")
|
|
990
|
+
# # ) SELECT * FROM "t"
|
|
797
991
|
def with_recursive(name, nonrecursive, recursive, opts={})
|
|
798
992
|
raise(Error, 'This datatset does not support common table expressions') unless supports_cte?
|
|
799
|
-
|
|
993
|
+
if hoist_cte?(nonrecursive)
|
|
994
|
+
s, ds = hoist_cte(nonrecursive)
|
|
995
|
+
s.with_recursive(name, ds, recursive, opts)
|
|
996
|
+
elsif hoist_cte?(recursive)
|
|
997
|
+
s, ds = hoist_cte(recursive)
|
|
998
|
+
s.with_recursive(name, nonrecursive, ds, opts)
|
|
999
|
+
else
|
|
1000
|
+
clone(:with=>(@opts[:with]||[]) + [opts.merge(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))])
|
|
1001
|
+
end
|
|
800
1002
|
end
|
|
801
1003
|
|
|
802
1004
|
# Returns a copy of the dataset with the static SQL used. This is useful if you want
|
|
803
1005
|
# to keep the same row_proc/graph, but change the SQL used to custom SQL.
|
|
804
1006
|
#
|
|
805
1007
|
# DB[:items].with_sql('SELECT * FROM foo') # SELECT * FROM foo
|
|
1008
|
+
#
|
|
1009
|
+
# You can use placeholders in your SQL and provide arguments for those placeholders:
|
|
1010
|
+
#
|
|
1011
|
+
# DB[:items].with_sql('SELECT ? FROM foo', 1) # SELECT 1 FROM foo
|
|
1012
|
+
#
|
|
1013
|
+
# You can also provide a method name and arguments to call to get the SQL:
|
|
1014
|
+
#
|
|
1015
|
+
# DB[:items].with_sql(:insert_sql, :b=>1) # INSERT INTO items (b) VALUES (1)
|
|
806
1016
|
def with_sql(sql, *args)
|
|
807
|
-
sql
|
|
1017
|
+
if sql.is_a?(Symbol)
|
|
1018
|
+
sql = send(sql, *args)
|
|
1019
|
+
else
|
|
1020
|
+
sql = SQL::PlaceholderLiteralString.new(sql, args) unless args.empty?
|
|
1021
|
+
end
|
|
808
1022
|
clone(:sql=>sql)
|
|
809
1023
|
end
|
|
810
1024
|
|
|
811
1025
|
protected
|
|
812
1026
|
|
|
1027
|
+
# Add the dataset to the list of compounds
|
|
1028
|
+
def compound_clone(type, dataset, opts)
|
|
1029
|
+
if hoist_cte?(dataset)
|
|
1030
|
+
s, ds = hoist_cte(dataset)
|
|
1031
|
+
return s.compound_clone(type, ds, opts)
|
|
1032
|
+
end
|
|
1033
|
+
ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map{|x| x.dup} + [[type, dataset.compound_from_self, opts[:all]]])
|
|
1034
|
+
opts[:from_self] == false ? ds : ds.from_self(opts)
|
|
1035
|
+
end
|
|
1036
|
+
|
|
813
1037
|
# Return true if the dataset has a non-nil value for any key in opts.
|
|
814
1038
|
def options_overlap(opts)
|
|
815
1039
|
!(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
|
|
@@ -823,22 +1047,22 @@ module Sequel
|
|
|
823
1047
|
|
|
824
1048
|
private
|
|
825
1049
|
|
|
826
|
-
# Internal filter method so it works on either the having or where clauses.
|
|
827
|
-
def
|
|
1050
|
+
# Internal filter/exclude method so it works on either the having or where clauses.
|
|
1051
|
+
def _filter_or_exclude(invert, clause, *cond, &block)
|
|
828
1052
|
cond = cond.first if cond.size == 1
|
|
829
1053
|
if cond.respond_to?(:empty?) && cond.empty? && !block
|
|
830
1054
|
clone
|
|
831
1055
|
else
|
|
832
1056
|
cond = filter_expr(cond, &block)
|
|
1057
|
+
cond = SQL::BooleanExpression.invert(cond) if invert
|
|
833
1058
|
cond = SQL::BooleanExpression.new(:AND, @opts[clause], cond) if @opts[clause]
|
|
834
1059
|
clone(clause => cond)
|
|
835
1060
|
end
|
|
836
1061
|
end
|
|
837
|
-
|
|
838
|
-
#
|
|
839
|
-
def
|
|
840
|
-
|
|
841
|
-
opts[:from_self] == false ? ds : ds.from_self(opts)
|
|
1062
|
+
|
|
1063
|
+
# Internal filter method so it works on either the having or where clauses.
|
|
1064
|
+
def _filter(clause, *cond, &block)
|
|
1065
|
+
_filter_or_exclude(false, clause, *cond, &block)
|
|
842
1066
|
end
|
|
843
1067
|
|
|
844
1068
|
# SQL expression object based on the expr type. See +filter+.
|
|
@@ -867,7 +1091,13 @@ module Sequel
|
|
|
867
1091
|
when Symbol, SQL::Expression
|
|
868
1092
|
expr
|
|
869
1093
|
when TrueClass, FalseClass
|
|
870
|
-
|
|
1094
|
+
if supports_where_true?
|
|
1095
|
+
SQL::BooleanExpression.new(:NOOP, expr)
|
|
1096
|
+
elsif expr
|
|
1097
|
+
SQL::Constants::SQLTRUE
|
|
1098
|
+
else
|
|
1099
|
+
SQL::Constants::SQLFALSE
|
|
1100
|
+
end
|
|
871
1101
|
when String
|
|
872
1102
|
LiteralString.new("(#{expr})")
|
|
873
1103
|
else
|
|
@@ -875,11 +1105,23 @@ module Sequel
|
|
|
875
1105
|
end
|
|
876
1106
|
end
|
|
877
1107
|
|
|
1108
|
+
# Return two datasets, the first a clone of the receiver with the WITH
|
|
1109
|
+
# clause from the given dataset added to it, and the second a clone of
|
|
1110
|
+
# the given dataset with the WITH clause removed.
|
|
1111
|
+
def hoist_cte(ds)
|
|
1112
|
+
[clone(:with => (opts[:with] || []) + ds.opts[:with]), ds.clone(:with => nil)]
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
# Whether CTEs need to be hoisted from the given ds into the current ds.
|
|
1116
|
+
def hoist_cte?(ds)
|
|
1117
|
+
ds.is_a?(Dataset) && ds.opts[:with] && !supports_cte_in_subqueries?
|
|
1118
|
+
end
|
|
1119
|
+
|
|
878
1120
|
# Inverts the given order by breaking it into a list of column references
|
|
879
1121
|
# and inverting them.
|
|
880
1122
|
#
|
|
881
|
-
# DB[:items].invert_order([:id
|
|
882
|
-
# DB[:items].invert_order(:category, :price
|
|
1123
|
+
# DB[:items].invert_order([Sequel.desc(:id)]]) #=> [Sequel.asc(:id)]
|
|
1124
|
+
# DB[:items].invert_order([:category, Sequel.desc(:price)]) #=> [Sequel.desc(:category), Sequel.asc(:price)]
|
|
883
1125
|
def invert_order(order)
|
|
884
1126
|
return nil unless order
|
|
885
1127
|
new_order = []
|
|
@@ -892,5 +1134,17 @@ module Sequel
|
|
|
892
1134
|
end
|
|
893
1135
|
end
|
|
894
1136
|
end
|
|
1137
|
+
|
|
1138
|
+
# Return self if the dataset already has a server, or a cloned dataset with the
|
|
1139
|
+
# default server otherwise.
|
|
1140
|
+
def default_server
|
|
1141
|
+
@opts[:server] ? self : clone(:server=>:default)
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
# Treat the +block+ as a virtual_row block if not +nil+ and
|
|
1145
|
+
# add the resulting columns to the +columns+ array (modifies +columns+).
|
|
1146
|
+
def virtual_row_columns(columns, block)
|
|
1147
|
+
columns.concat(Array(Sequel.virtual_row(&block))) if block
|
|
1148
|
+
end
|
|
895
1149
|
end
|
|
896
1150
|
end
|