sequel 4.41.0 → 4.42.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 +98 -0
- data/README.rdoc +23 -10
- data/doc/active_record.rdoc +4 -4
- data/doc/advanced_associations.rdoc +2 -2
- data/doc/association_basics.rdoc +5 -2
- data/doc/cheat_sheet.rdoc +3 -3
- data/doc/core_extensions.rdoc +2 -2
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/migration.rdoc +19 -1
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/release_notes/4.42.0.txt +221 -0
- data/doc/testing.rdoc +3 -1
- data/lib/sequel/adapters/ado/access.rb +0 -1
- data/lib/sequel/adapters/ado/mssql.rb +0 -1
- data/lib/sequel/adapters/do/mysql.rb +0 -1
- data/lib/sequel/adapters/do/postgres.rb +0 -1
- data/lib/sequel/adapters/do/sqlite3.rb +0 -1
- data/lib/sequel/adapters/ibmdb.rb +21 -25
- data/lib/sequel/adapters/jdbc.rb +8 -16
- data/lib/sequel/adapters/jdbc/as400.rb +0 -1
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -1
- data/lib/sequel/adapters/jdbc/db2.rb +0 -1
- data/lib/sequel/adapters/jdbc/derby.rb +0 -1
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -1
- data/lib/sequel/adapters/jdbc/h2.rb +0 -1
- data/lib/sequel/adapters/jdbc/hsqldb.rb +0 -1
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -1
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +0 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -13
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +0 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -4
- data/lib/sequel/adapters/mock.rb +54 -12
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +11 -17
- data/lib/sequel/adapters/odbc/mssql.rb +0 -1
- data/lib/sequel/adapters/oracle.rb +8 -20
- data/lib/sequel/adapters/postgres.rb +11 -29
- data/lib/sequel/adapters/shared/access.rb +5 -12
- data/lib/sequel/adapters/shared/cubrid.rb +4 -13
- data/lib/sequel/adapters/shared/db2.rb +4 -2
- data/lib/sequel/adapters/shared/firebird.rb +2 -4
- data/lib/sequel/adapters/shared/informix.rb +4 -2
- data/lib/sequel/adapters/shared/mssql.rb +3 -5
- data/lib/sequel/adapters/shared/mysql.rb +4 -14
- data/lib/sequel/adapters/shared/oracle.rb +1 -3
- data/lib/sequel/adapters/shared/postgres.rb +16 -38
- data/lib/sequel/adapters/shared/progress.rb +0 -2
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -2
- data/lib/sequel/adapters/shared/sqlite.rb +20 -16
- data/lib/sequel/adapters/sqlite.rb +8 -20
- data/lib/sequel/adapters/swift/mysql.rb +0 -1
- data/lib/sequel/adapters/swift/postgres.rb +0 -1
- data/lib/sequel/adapters/swift/sqlite.rb +0 -1
- data/lib/sequel/adapters/tinytds.rb +4 -12
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -2
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +11 -34
- data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +26 -0
- data/lib/sequel/ast_transformer.rb +2 -2
- data/lib/sequel/database/dataset.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +0 -66
- data/lib/sequel/database/features.rb +6 -0
- data/lib/sequel/database/misc.rb +31 -17
- data/lib/sequel/database/query.rb +7 -4
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset.rb +8 -8
- data/lib/sequel/dataset/actions.rb +140 -46
- data/lib/sequel/dataset/features.rb +1 -5
- data/lib/sequel/dataset/graph.rb +7 -8
- data/lib/sequel/dataset/misc.rb +127 -56
- data/lib/sequel/dataset/mutation.rb +9 -20
- data/lib/sequel/dataset/placeholder_literalizer.rb +10 -1
- data/lib/sequel/dataset/prepared_statements.rb +102 -46
- data/lib/sequel/dataset/query.rb +155 -72
- data/lib/sequel/dataset/sql.rb +26 -9
- data/lib/sequel/extensions/columns_introspection.rb +3 -1
- data/lib/sequel/extensions/core_extensions.rb +5 -5
- data/lib/sequel/extensions/core_refinements.rb +5 -5
- data/lib/sequel/extensions/duplicate_columns_handler.rb +4 -2
- data/lib/sequel/extensions/freeze_datasets.rb +69 -0
- data/lib/sequel/extensions/identifier_mangling.rb +196 -0
- data/lib/sequel/extensions/looser_typecasting.rb +11 -7
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/null_dataset.rb +5 -2
- data/lib/sequel/extensions/pagination.rb +42 -23
- data/lib/sequel/extensions/pg_enum.rb +3 -3
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +15 -8
- data/lib/sequel/model/associations.rb +25 -8
- data/lib/sequel/model/base.rb +88 -29
- data/lib/sequel/model/dataset_module.rb +37 -0
- data/lib/sequel/plugins/association_pks.rb +4 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/constraint_validations.rb +1 -2
- data/lib/sequel/plugins/csv_serializer.rb +2 -2
- data/lib/sequel/plugins/dataset_associations.rb +8 -8
- data/lib/sequel/plugins/eager_each.rb +2 -2
- data/lib/sequel/plugins/instance_filters.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/list.rb +4 -4
- data/lib/sequel/plugins/prepared_statements.rb +2 -4
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -3
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +13 -13
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +9 -4
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +2 -2
- data/lib/sequel/sql.rb +69 -36
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +10 -0
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +4 -5
- data/spec/adapters/mysql_spec.rb +9 -9
- data/spec/adapters/postgres_spec.rb +67 -68
- data/spec/adapters/spec_helper.rb +6 -1
- data/spec/adapters/sqlite_spec.rb +29 -15
- data/spec/core/connection_pool_spec.rb +14 -14
- data/spec/core/database_spec.rb +38 -180
- data/spec/core/dataset_mutation_spec.rb +253 -0
- data/spec/core/dataset_spec.rb +394 -537
- data/spec/core/expression_filters_spec.rb +34 -32
- data/spec/core/mock_adapter_spec.rb +27 -35
- data/spec/core/placeholder_literalizer_spec.rb +2 -4
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +1 -2
- data/spec/core_extensions_spec.rb +22 -29
- data/spec/extensions/active_model_spec.rb +6 -6
- data/spec/extensions/association_dependencies_spec.rb +2 -2
- data/spec/extensions/blacklist_security_spec.rb +3 -3
- data/spec/extensions/boolean_readers_spec.rb +12 -12
- data/spec/extensions/caching_spec.rb +13 -10
- data/spec/extensions/class_table_inheritance_spec.rb +38 -43
- data/spec/extensions/column_conflicts_spec.rb +1 -3
- data/spec/extensions/columns_introspection_spec.rb +2 -3
- data/spec/extensions/composition_spec.rb +5 -3
- data/spec/extensions/constraint_validations_plugin_spec.rb +5 -5
- data/spec/extensions/constraint_validations_spec.rb +14 -8
- data/spec/extensions/core_refinements_spec.rb +22 -29
- data/spec/extensions/csv_serializer_spec.rb +7 -6
- data/spec/extensions/date_arithmetic_spec.rb +15 -15
- data/spec/extensions/defaults_setter_spec.rb +2 -2
- data/spec/extensions/delay_add_association_spec.rb +1 -1
- data/spec/extensions/dirty_spec.rb +19 -10
- data/spec/extensions/duplicate_columns_handler_spec.rb +12 -18
- data/spec/extensions/eager_each_spec.rb +12 -16
- data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
- data/spec/extensions/eval_inspect_spec.rb +4 -3
- data/spec/extensions/force_encoding_spec.rb +12 -12
- data/spec/extensions/freeze_datasets_spec.rb +31 -0
- data/spec/extensions/graph_each_spec.rb +6 -18
- data/spec/extensions/hook_class_methods_spec.rb +7 -7
- data/spec/extensions/identifier_mangling_spec.rb +307 -0
- data/spec/extensions/instance_filters_spec.rb +5 -6
- data/spec/extensions/instance_hooks_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +12 -15
- data/spec/extensions/lazy_attributes_spec.rb +4 -4
- data/spec/extensions/list_spec.rb +19 -21
- data/spec/extensions/many_through_many_spec.rb +108 -163
- data/spec/extensions/meta_def_spec.rb +7 -2
- data/spec/extensions/migration_spec.rb +10 -12
- data/spec/extensions/mssql_optimistic_locking_spec.rb +4 -3
- data/spec/extensions/named_timezones_spec.rb +4 -3
- data/spec/extensions/nested_attributes_spec.rb +2 -2
- data/spec/extensions/null_dataset_spec.rb +17 -12
- data/spec/extensions/optimistic_locking_spec.rb +4 -5
- data/spec/extensions/pagination_spec.rb +8 -10
- data/spec/extensions/pg_array_associations_spec.rb +28 -27
- data/spec/extensions/pg_array_ops_spec.rb +2 -1
- data/spec/extensions/pg_array_spec.rb +6 -2
- data/spec/extensions/pg_enum_spec.rb +5 -3
- data/spec/extensions/pg_hstore_ops_spec.rb +3 -1
- data/spec/extensions/pg_hstore_spec.rb +7 -6
- data/spec/extensions/pg_inet_ops_spec.rb +2 -1
- data/spec/extensions/pg_inet_spec.rb +2 -1
- data/spec/extensions/pg_interval_spec.rb +2 -1
- data/spec/extensions/pg_json_ops_spec.rb +2 -1
- data/spec/extensions/pg_json_spec.rb +6 -3
- data/spec/extensions/pg_loose_count_spec.rb +1 -0
- data/spec/extensions/pg_range_ops_spec.rb +3 -1
- data/spec/extensions/pg_range_spec.rb +9 -5
- data/spec/extensions/pg_row_ops_spec.rb +2 -1
- data/spec/extensions/pg_row_plugin_spec.rb +4 -6
- data/spec/extensions/pg_row_spec.rb +5 -3
- data/spec/extensions/pg_static_cache_updater_spec.rb +2 -1
- data/spec/extensions/pg_typecast_on_load_spec.rb +1 -1
- data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
- data/spec/extensions/prepared_statements_spec.rb +12 -11
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +8 -5
- data/spec/extensions/rcte_tree_spec.rb +39 -39
- data/spec/extensions/round_timestamps_spec.rb +2 -2
- data/spec/extensions/schema_dumper_spec.rb +3 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/scissors_spec.rb +1 -2
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +30 -17
- data/spec/extensions/serialization_modification_detection_spec.rb +2 -2
- data/spec/extensions/serialization_spec.rb +15 -13
- data/spec/extensions/set_overrides_spec.rb +14 -8
- data/spec/extensions/sharding_spec.rb +9 -18
- data/spec/extensions/shared_caching_spec.rb +3 -4
- data/spec/extensions/single_table_inheritance_spec.rb +11 -11
- data/spec/extensions/skip_create_refresh_spec.rb +2 -1
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/split_values_spec.rb +2 -2
- data/spec/extensions/sql_comments_spec.rb +6 -0
- data/spec/extensions/static_cache_spec.rb +7 -9
- data/spec/extensions/string_agg_spec.rb +30 -29
- data/spec/extensions/tactical_eager_loading_spec.rb +4 -5
- data/spec/extensions/thread_local_timezones_spec.rb +2 -2
- data/spec/extensions/timestamps_spec.rb +28 -3
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/tree_spec.rb +33 -29
- data/spec/extensions/typecast_on_load_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +1 -0
- data/spec/extensions/update_primary_key_spec.rb +11 -7
- data/spec/extensions/update_refresh_spec.rb +1 -1
- data/spec/extensions/uuid_spec.rb +0 -1
- data/spec/extensions/validate_associated_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +10 -10
- data/spec/extensions/validation_helpers_spec.rb +10 -10
- data/spec/extensions/xml_serializer_spec.rb +7 -3
- data/spec/integration/associations_test.rb +31 -31
- data/spec/integration/dataset_test.rb +17 -19
- data/spec/integration/eager_loader_test.rb +24 -24
- data/spec/integration/model_test.rb +6 -6
- data/spec/integration/plugin_test.rb +43 -43
- data/spec/integration/prepared_statement_test.rb +6 -6
- data/spec/integration/schema_test.rb +63 -52
- data/spec/integration/spec_helper.rb +6 -1
- data/spec/integration/transaction_test.rb +13 -13
- data/spec/model/association_reflection_spec.rb +17 -17
- data/spec/model/associations_spec.rb +101 -96
- data/spec/model/base_spec.rb +175 -49
- data/spec/model/class_dataset_methods_spec.rb +5 -9
- data/spec/model/dataset_methods_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +209 -235
- data/spec/model/hooks_spec.rb +15 -15
- data/spec/model/model_spec.rb +28 -21
- data/spec/model/plugins_spec.rb +4 -5
- data/spec/model/record_spec.rb +59 -57
- data/spec/model/spec_helper.rb +1 -1
- data/spec/model/validations_spec.rb +6 -6
- data/spec/spec_config.rb +1 -1
- metadata +10 -2
|
@@ -115,6 +115,12 @@ module Sequel
|
|
|
115
115
|
true
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# Whether this dataset considers unquoted identifiers as uppercase. True
|
|
119
|
+
# by default as that is the SQL standard
|
|
120
|
+
def folds_unquoted_identifiers_to_uppercase?
|
|
121
|
+
true
|
|
122
|
+
end
|
|
123
|
+
|
|
118
124
|
# Whether the database supports combining multiple alter table
|
|
119
125
|
# operations into a single query, false by default.
|
|
120
126
|
def supports_combining_alter_table_ops?
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -30,7 +30,10 @@ module Sequel
|
|
|
30
30
|
# included in the database, the identifier mangling defaults are reset correctly.
|
|
31
31
|
module ResetIdentifierMangling
|
|
32
32
|
def extended(obj)
|
|
33
|
-
|
|
33
|
+
# :nocov:
|
|
34
|
+
Sequel::Deprecation.deprecate("Sequel::Database::ResetIdentifierMangling is no longer needed and will be removed in Sequel 5. Please update your adapter.")
|
|
35
|
+
obj.send(:reset_identifier_mangling) if obj.respond_to?(:reset_identifier_mangling)
|
|
36
|
+
# :nocov:
|
|
34
37
|
end
|
|
35
38
|
end
|
|
36
39
|
|
|
@@ -104,8 +107,7 @@ module Sequel
|
|
|
104
107
|
#
|
|
105
108
|
# Accepts the following options:
|
|
106
109
|
# :default_string_column_size :: The default size of string columns, 255 by default.
|
|
107
|
-
# :
|
|
108
|
-
# :identifier_output_method :: A string method symbol to call on identifiers coming from the database.
|
|
110
|
+
# :identifier_mangling :: Whether to support non-default identifier mangling for the current database.
|
|
109
111
|
# :logger :: A specific logger to use.
|
|
110
112
|
# :loggers :: An array of loggers to use.
|
|
111
113
|
# :name :: A name to use for the Database object.
|
|
@@ -131,9 +133,6 @@ module Sequel
|
|
|
131
133
|
@transactions = {}
|
|
132
134
|
@symbol_literal_cache = {}
|
|
133
135
|
|
|
134
|
-
@identifier_input_method = nil
|
|
135
|
-
@identifier_output_method = nil
|
|
136
|
-
@quote_identifiers = nil
|
|
137
136
|
@timezone = nil
|
|
138
137
|
|
|
139
138
|
@dataset_class = dataset_class_default
|
|
@@ -147,8 +146,11 @@ module Sequel
|
|
|
147
146
|
|
|
148
147
|
@pool = ConnectionPool.get_pool(self, @opts)
|
|
149
148
|
|
|
150
|
-
|
|
149
|
+
reset_default_dataset
|
|
151
150
|
adapter_initialize
|
|
151
|
+
if typecast_value_boolean(@opts.fetch(:identifier_mangling, true))
|
|
152
|
+
extension(:identifier_mangling)
|
|
153
|
+
end
|
|
152
154
|
|
|
153
155
|
unless typecast_value_boolean(@opts[:keep_reference]) == false
|
|
154
156
|
Sequel.synchronize{::Sequel::DATABASES.push(self)}
|
|
@@ -248,7 +250,6 @@ module Sequel
|
|
|
248
250
|
|
|
249
251
|
# Cache the prepared statement object at the given name.
|
|
250
252
|
def set_prepared_statement(name, ps)
|
|
251
|
-
ps.prepared_sql
|
|
252
253
|
Sequel.synchronize{prepared_statements[name] = ps}
|
|
253
254
|
end
|
|
254
255
|
|
|
@@ -429,15 +430,15 @@ module Sequel
|
|
|
429
430
|
def typecast_value_datetime(value)
|
|
430
431
|
Sequel.typecast_to_application_timestamp(value)
|
|
431
432
|
end
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
433
|
+
|
|
434
|
+
if RUBY_VERSION >= '2.4'
|
|
435
|
+
# Typecast a string to a BigDecimal
|
|
436
|
+
def _typecast_value_string_to_decimal(value)
|
|
437
|
+
BigDecimal.new(value)
|
|
438
|
+
end
|
|
439
|
+
else
|
|
440
|
+
# :nocov:
|
|
441
|
+
def _typecast_value_string_to_decimal(value)
|
|
441
442
|
d = BigDecimal.new(value)
|
|
442
443
|
if d.zero?
|
|
443
444
|
# BigDecimal parsing is loose by default, returning a 0 value for
|
|
@@ -450,6 +451,19 @@ module Sequel
|
|
|
450
451
|
end
|
|
451
452
|
end
|
|
452
453
|
d
|
|
454
|
+
end
|
|
455
|
+
# :nocov:
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Typecast the value to a BigDecimal
|
|
459
|
+
def typecast_value_decimal(value)
|
|
460
|
+
case value
|
|
461
|
+
when BigDecimal
|
|
462
|
+
value
|
|
463
|
+
when Numeric
|
|
464
|
+
BigDecimal.new(value.to_s)
|
|
465
|
+
when String
|
|
466
|
+
_typecast_value_string_to_decimal(value)
|
|
453
467
|
else
|
|
454
468
|
raise InvalidValue, "invalid value for BigDecimal: #{value.inspect}"
|
|
455
469
|
end
|
|
@@ -32,7 +32,7 @@ module Sequel
|
|
|
32
32
|
# Call the prepared statement with the given name with the given hash
|
|
33
33
|
# of arguments.
|
|
34
34
|
#
|
|
35
|
-
# DB[:items].
|
|
35
|
+
# DB[:items].where(:id=>1).prepare(:first, :sa)
|
|
36
36
|
# DB.call(:sa) # SELECT * FROM items WHERE id = 1
|
|
37
37
|
def call(ps_name, hash={}, &block)
|
|
38
38
|
prepared_statement(ps_name).call(hash, &block)
|
|
@@ -287,13 +287,16 @@ module Sequel
|
|
|
287
287
|
(ds || dataset).method(:input_identifier)
|
|
288
288
|
end
|
|
289
289
|
|
|
290
|
+
# Uncached version of metadata_dataset, designed for overriding.
|
|
291
|
+
def _metadata_dataset
|
|
292
|
+
dataset
|
|
293
|
+
end
|
|
294
|
+
|
|
290
295
|
# Return a dataset that uses the default identifier input and output methods
|
|
291
296
|
# for this database. Used when parsing metadata so that column symbols are
|
|
292
297
|
# returned as expected.
|
|
293
298
|
def metadata_dataset
|
|
294
|
-
@metadata_dataset ||=
|
|
295
|
-
with_identifier_input_method(identifier_input_method_default).
|
|
296
|
-
with_identifier_output_method(identifier_output_method_default)
|
|
299
|
+
@metadata_dataset ||= _metadata_dataset
|
|
297
300
|
end
|
|
298
301
|
|
|
299
302
|
# Return a Method object for the dataset's output_identifier_method.
|
|
@@ -235,7 +235,7 @@ module Sequel
|
|
|
235
235
|
# Creates a view, replacing a view with the same name if one already exists.
|
|
236
236
|
#
|
|
237
237
|
# DB.create_or_replace_view(:some_items, "SELECT * FROM items WHERE price < 100")
|
|
238
|
-
# DB.create_or_replace_view(:some_items, DB[:items].
|
|
238
|
+
# DB.create_or_replace_view(:some_items, DB[:items].where(:category => 'ruby'))
|
|
239
239
|
#
|
|
240
240
|
# For databases where replacing a view is not natively supported, support
|
|
241
241
|
# is emulated by dropping a view with the same name before creating the view.
|
data/lib/sequel/dataset.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Sequel
|
|
|
8
8
|
# Query results are always retrieved on demand, so a dataset can be kept
|
|
9
9
|
# around and reused indefinitely (datasets never cache results):
|
|
10
10
|
#
|
|
11
|
-
# my_posts = DB[:posts].
|
|
11
|
+
# my_posts = DB[:posts].where(:author => 'david') # no records are retrieved
|
|
12
12
|
# my_posts.all # records are retrieved
|
|
13
13
|
# my_posts.all # records are retrieved again
|
|
14
14
|
#
|
|
@@ -16,9 +16,9 @@ module Sequel
|
|
|
16
16
|
# reuse different datasets to access data:
|
|
17
17
|
#
|
|
18
18
|
# posts = DB[:posts]
|
|
19
|
-
# davids_posts = posts.
|
|
20
|
-
# old_posts = posts.
|
|
21
|
-
# davids_old_posts = davids_posts.
|
|
19
|
+
# davids_posts = posts.where(:author => 'david')
|
|
20
|
+
# old_posts = posts.where('stamp < ?', Date.today - 7)
|
|
21
|
+
# davids_old_posts = davids_posts.where('stamp < ?', Date.today - 7)
|
|
22
22
|
#
|
|
23
23
|
# Datasets are Enumerable objects, so they can be manipulated using any
|
|
24
24
|
# of the Enumerable methods, such as map, inject, etc.
|
|
@@ -27,6 +27,10 @@ module Sequel
|
|
|
27
27
|
class Dataset
|
|
28
28
|
OPTS = Sequel::OPTS
|
|
29
29
|
|
|
30
|
+
# Whether Dataset#freeze can actually freeze datasets. True only on ruby 2.4+,
|
|
31
|
+
# as it requires clone(freeze: false)
|
|
32
|
+
TRUE_FREEZE = RUBY_VERSION >= '2.4'
|
|
33
|
+
|
|
30
34
|
include Enumerable
|
|
31
35
|
include SQL::AliasMethods
|
|
32
36
|
include SQL::BooleanMethods
|
|
@@ -36,10 +40,6 @@ module Sequel
|
|
|
36
40
|
include SQL::NumericMethods
|
|
37
41
|
include SQL::OrderMethods
|
|
38
42
|
include SQL::StringMethods
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
attr_writer :columns
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
require(%w"query actions features graph prepared_statements misc mutation sql placeholder_literalizer", 'dataset')
|
|
@@ -17,6 +17,9 @@ module Sequel
|
|
|
17
17
|
single_record single_record! single_value single_value! sum to_hash to_hash_groups truncate update
|
|
18
18
|
METHS
|
|
19
19
|
|
|
20
|
+
# The clone options to use when retriveing columns for a dataset.
|
|
21
|
+
COLUMNS_CLONE_OPTIONS = {:distinct => nil, :limit => 1, :offset=>nil, :where=>nil, :having=>nil, :order=>nil, :row_proc=>nil, :graph=>nil, :eager_graph=>nil}.freeze
|
|
22
|
+
|
|
20
23
|
# Inserts the given argument into the database. Returns self so it
|
|
21
24
|
# can be used safely when chaining:
|
|
22
25
|
#
|
|
@@ -54,8 +57,8 @@ module Sequel
|
|
|
54
57
|
# # => 3
|
|
55
58
|
# DB[:table].avg{function(column)} # SELECT avg(function(column)) FROM table LIMIT 1
|
|
56
59
|
# # => 1
|
|
57
|
-
def avg(
|
|
58
|
-
|
|
60
|
+
def avg(arg=Sequel.virtual_row(&Proc.new))
|
|
61
|
+
_aggregate(:avg, arg)
|
|
59
62
|
end
|
|
60
63
|
|
|
61
64
|
# Returns the columns in the result set in order as an array of symbols.
|
|
@@ -68,11 +71,7 @@ module Sequel
|
|
|
68
71
|
# DB[:table].columns
|
|
69
72
|
# # => [:id, :name]
|
|
70
73
|
def columns
|
|
71
|
-
|
|
72
|
-
ds = unfiltered.unordered.naked.clone(:distinct => nil, :limit => 1, :offset=>nil)
|
|
73
|
-
ds.each{break}
|
|
74
|
-
@columns = ds.instance_variable_get(:@columns)
|
|
75
|
-
@columns || []
|
|
74
|
+
_columns || columns!
|
|
76
75
|
end
|
|
77
76
|
|
|
78
77
|
# Ignore any cached column information and perform a query to retrieve
|
|
@@ -81,8 +80,14 @@ module Sequel
|
|
|
81
80
|
# DB[:table].columns!
|
|
82
81
|
# # => [:id, :name]
|
|
83
82
|
def columns!
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
ds = clone(COLUMNS_CLONE_OPTIONS)
|
|
84
|
+
ds.each{break}
|
|
85
|
+
|
|
86
|
+
if cols = ds.cache[:_columns]
|
|
87
|
+
self.columns = cols
|
|
88
|
+
else
|
|
89
|
+
[]
|
|
90
|
+
end
|
|
86
91
|
end
|
|
87
92
|
|
|
88
93
|
# Returns the number of records in the dataset. If an argument is provided,
|
|
@@ -97,20 +102,23 @@ module Sequel
|
|
|
97
102
|
# DB[:table].count{foo(column)} # SELECT count(foo(column)) AS count FROM table LIMIT 1
|
|
98
103
|
# # => 1
|
|
99
104
|
def count(arg=(no_arg=true), &block)
|
|
100
|
-
if no_arg
|
|
105
|
+
if no_arg && !block
|
|
106
|
+
cached_dataset(:_count_ds) do
|
|
107
|
+
aggregate_dataset.select{count{}.*.as(:count)}.single_value_ds
|
|
108
|
+
end.single_value!.to_i
|
|
109
|
+
else
|
|
101
110
|
if block
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
if no_arg
|
|
112
|
+
arg = Sequel.virtual_row(&block)
|
|
113
|
+
else
|
|
114
|
+
raise Error, 'cannot provide both argument and block to Dataset#count'
|
|
115
|
+
end
|
|
106
116
|
end
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
else
|
|
110
|
-
aggregate_dataset.get{count(arg).as(:count)}
|
|
117
|
+
|
|
118
|
+
_aggregate(:count, arg)
|
|
111
119
|
end
|
|
112
120
|
end
|
|
113
|
-
|
|
121
|
+
|
|
114
122
|
# Deletes the records in the dataset. The returned value should be
|
|
115
123
|
# number of records deleted, but that is adapter dependent.
|
|
116
124
|
#
|
|
@@ -148,8 +156,9 @@ module Sequel
|
|
|
148
156
|
# DB[:table].empty? # SELECT 1 AS one FROM table LIMIT 1
|
|
149
157
|
# # => false
|
|
150
158
|
def empty?
|
|
151
|
-
|
|
152
|
-
|
|
159
|
+
cached_dataset(:_empty_ds) do
|
|
160
|
+
single_value_ds.unordered.select(Sequel::SQL::AliasedExpression.new(1, :one))
|
|
161
|
+
end.single_value!.nil?
|
|
153
162
|
end
|
|
154
163
|
|
|
155
164
|
# If a integer argument is given, it is interpreted as a limit, and then returns all
|
|
@@ -188,17 +197,46 @@ module Sequel
|
|
|
188
197
|
# DB[:table].first(2){id < 2} # SELECT * FROM table WHERE (id < 2) LIMIT 2
|
|
189
198
|
# # => [{:id=>1}]
|
|
190
199
|
def first(*args, &block)
|
|
191
|
-
|
|
200
|
+
case args.length
|
|
201
|
+
when 0
|
|
202
|
+
unless block
|
|
203
|
+
return single_record
|
|
204
|
+
end
|
|
205
|
+
when 1
|
|
206
|
+
arg = args[0]
|
|
207
|
+
if arg.is_a?(Integer)
|
|
208
|
+
res = if block
|
|
209
|
+
if loader = cached_placeholder_literalizer(:_first_integer_cond_loader) do |pl|
|
|
210
|
+
where(pl.arg).limit(pl.arg)
|
|
211
|
+
end
|
|
192
212
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
213
|
+
loader.all(filter_expr(&block), arg)
|
|
214
|
+
else
|
|
215
|
+
where(&block).limit(arg).all
|
|
216
|
+
end
|
|
217
|
+
else
|
|
218
|
+
if loader = cached_placeholder_literalizer(:_first_integer_loader) do |pl|
|
|
219
|
+
limit(pl.arg)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
loader.all(arg)
|
|
223
|
+
else
|
|
224
|
+
limit(arg).all
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
return res
|
|
201
229
|
end
|
|
230
|
+
args = arg
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
if loader = cached_placeholder_literalizer(:_first_cond_loader) do |pl|
|
|
234
|
+
_single_record_ds.where(pl.arg)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
loader.first(filter_expr(args, &block))
|
|
238
|
+
else
|
|
239
|
+
_single_record_ds.where(args, &block).single_record!
|
|
202
240
|
end
|
|
203
241
|
end
|
|
204
242
|
|
|
@@ -234,10 +272,27 @@ module Sequel
|
|
|
234
272
|
column = ds.opts[:select]
|
|
235
273
|
column = nil if column.is_a?(Array) && column.length < 2
|
|
236
274
|
else
|
|
237
|
-
|
|
238
|
-
|
|
275
|
+
case column
|
|
276
|
+
when Array
|
|
277
|
+
ds = ds.select(*column)
|
|
278
|
+
when LiteralString, Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression
|
|
279
|
+
if loader = cached_placeholder_literalizer(:_get_loader) do |pl|
|
|
280
|
+
ds.single_value_ds.select(pl.arg)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
return loader.get(column)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
ds = ds.select(column)
|
|
239
287
|
else
|
|
240
|
-
|
|
288
|
+
if loader = cached_placeholder_literalizer(:_get_alias_loader) do |pl|
|
|
289
|
+
ds.single_value_ds.select(Sequel.as(pl.arg, :v))
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
return loader.get(column)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
ds = ds.select(Sequel.as(column, :v))
|
|
241
296
|
end
|
|
242
297
|
end
|
|
243
298
|
|
|
@@ -347,7 +402,15 @@ module Sequel
|
|
|
347
402
|
# DB[:table].interval{function(column)} # SELECT (max(function(column)) - min(function(column))) FROM table LIMIT 1
|
|
348
403
|
# # => 7
|
|
349
404
|
def interval(column=Sequel.virtual_row(&Proc.new))
|
|
350
|
-
|
|
405
|
+
if loader = cached_placeholder_literalizer(:_interval_loader) do |pl|
|
|
406
|
+
arg = pl.arg
|
|
407
|
+
aggregate_dataset.limit(1).select((SQL::Function.new(:max, arg) - SQL::Function.new(:min, arg)).as(:interval))
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
loader.get(column)
|
|
411
|
+
else
|
|
412
|
+
aggregate_dataset.get{(max(column) - min(column)).as(:interval)}
|
|
413
|
+
end
|
|
351
414
|
end
|
|
352
415
|
|
|
353
416
|
# Reverses the order and then runs #first with the given arguments and block. Note that this
|
|
@@ -400,8 +463,8 @@ module Sequel
|
|
|
400
463
|
# # => 10
|
|
401
464
|
# DB[:table].max{function(column)} # SELECT max(function(column)) FROM table LIMIT 1
|
|
402
465
|
# # => 7
|
|
403
|
-
def max(
|
|
404
|
-
|
|
466
|
+
def max(arg=Sequel.virtual_row(&Proc.new))
|
|
467
|
+
_aggregate(:max, arg)
|
|
405
468
|
end
|
|
406
469
|
|
|
407
470
|
# Returns the minimum value for the given column/expression.
|
|
@@ -411,8 +474,8 @@ module Sequel
|
|
|
411
474
|
# # => 1
|
|
412
475
|
# DB[:table].min{function(column)} # SELECT min(function(column)) FROM table LIMIT 1
|
|
413
476
|
# # => 0
|
|
414
|
-
def min(
|
|
415
|
-
|
|
477
|
+
def min(arg=Sequel.virtual_row(&Proc.new))
|
|
478
|
+
_aggregate(:min, arg)
|
|
416
479
|
end
|
|
417
480
|
|
|
418
481
|
# This is a front end for import that allows you to submit an array of
|
|
@@ -552,7 +615,17 @@ module Sequel
|
|
|
552
615
|
# DB[:table].interval{function(column)} # SELECT max(function(column)) AS v1, min(function(column)) AS v2 FROM table LIMIT 1
|
|
553
616
|
# # => 0..7
|
|
554
617
|
def range(column=Sequel.virtual_row(&Proc.new))
|
|
555
|
-
if
|
|
618
|
+
r = if loader = cached_placeholder_literalizer(:_range_loader) do |pl|
|
|
619
|
+
arg = pl.arg
|
|
620
|
+
aggregate_dataset.limit(1).select(SQL::Function.new(:min, arg).as(:v1), SQL::Function.new(:max, arg).as(:v2))
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
loader.first(column)
|
|
624
|
+
else
|
|
625
|
+
aggregate_dataset.select{[min(column).as(v1), max(column).as(v2)]}.first
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
if r
|
|
556
629
|
(r[:v1]..r[:v2])
|
|
557
630
|
end
|
|
558
631
|
end
|
|
@@ -649,7 +722,7 @@ module Sequel
|
|
|
649
722
|
# DB[:test].single_record # SELECT * FROM test LIMIT 1
|
|
650
723
|
# # => {:column_name=>'value'}
|
|
651
724
|
def single_record
|
|
652
|
-
|
|
725
|
+
_single_record_ds.single_record!
|
|
653
726
|
end
|
|
654
727
|
|
|
655
728
|
# Returns the first record in dataset, without limiting the dataset. Returns nil if
|
|
@@ -671,9 +744,10 @@ module Sequel
|
|
|
671
744
|
# DB[:test].single_value # SELECT * FROM test LIMIT 1
|
|
672
745
|
# # => 'value'
|
|
673
746
|
def single_value
|
|
674
|
-
|
|
747
|
+
single_value_ds.each do |r|
|
|
675
748
|
r.each{|_, v| return v}
|
|
676
749
|
end
|
|
750
|
+
nil
|
|
677
751
|
end
|
|
678
752
|
|
|
679
753
|
# Returns the first value of the first record in the dataset, without limiting the dataset.
|
|
@@ -695,8 +769,8 @@ module Sequel
|
|
|
695
769
|
# # => 55
|
|
696
770
|
# DB[:table].sum{function(column)} # SELECT sum(function(column)) FROM table LIMIT 1
|
|
697
771
|
# # => 10
|
|
698
|
-
def sum(
|
|
699
|
-
|
|
772
|
+
def sum(arg=Sequel.virtual_row(&Proc.new))
|
|
773
|
+
_aggregate(:sum, arg)
|
|
700
774
|
end
|
|
701
775
|
|
|
702
776
|
# Returns a hash with one column used as key and another used as value.
|
|
@@ -902,6 +976,11 @@ module Sequel
|
|
|
902
976
|
map{|r| r.values.first}
|
|
903
977
|
end
|
|
904
978
|
|
|
979
|
+
# A dataset for returning single values from the current dataset.
|
|
980
|
+
def single_value_ds
|
|
981
|
+
clone(:limit=>1).ungraphed.naked
|
|
982
|
+
end
|
|
983
|
+
|
|
905
984
|
private
|
|
906
985
|
|
|
907
986
|
# Internals of all and with_sql_all
|
|
@@ -913,6 +992,17 @@ module Sequel
|
|
|
913
992
|
a
|
|
914
993
|
end
|
|
915
994
|
|
|
995
|
+
# Cached placeholder literalizer for methods that return values using aggregate functions.
|
|
996
|
+
def _aggregate(function, arg)
|
|
997
|
+
if loader = cached_placeholder_literalizer(:"_#{function}_loader") do |pl|
|
|
998
|
+
aggregate_dataset.limit(1).select(SQL::Function.new(function, pl.arg).as(function))
|
|
999
|
+
end
|
|
1000
|
+
loader.get(arg)
|
|
1001
|
+
else
|
|
1002
|
+
aggregate_dataset.get(SQL::Function.new(function, arg).as(function))
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
|
|
916
1006
|
# Internals of +select_hash+ and +select_hash_groups+
|
|
917
1007
|
def _select_hash(meth, key_column, value_column, opts=OPTS)
|
|
918
1008
|
select(*(key_column.is_a?(Array) ? key_column : [key_column]) + (value_column.is_a?(Array) ? value_column : [value_column])).
|
|
@@ -933,6 +1023,11 @@ module Sequel
|
|
|
933
1023
|
end
|
|
934
1024
|
end
|
|
935
1025
|
|
|
1026
|
+
# A cached dataset for a single record for this dataset.
|
|
1027
|
+
def _single_record_ds
|
|
1028
|
+
cached_dataset(:_single_record_ds){clone(:limit=>1)}
|
|
1029
|
+
end
|
|
1030
|
+
|
|
936
1031
|
# Automatically alias the given expression if it does not have an identifiable alias.
|
|
937
1032
|
def auto_alias_expression(v)
|
|
938
1033
|
case v
|
|
@@ -1052,11 +1147,10 @@ module Sequel
|
|
|
1052
1147
|
Sequel.|(*cond)
|
|
1053
1148
|
end
|
|
1054
1149
|
|
|
1055
|
-
#
|
|
1056
|
-
# identifier_output_method.
|
|
1150
|
+
# Downcase identifiers by default when outputing them from the database.
|
|
1057
1151
|
def output_identifier(v)
|
|
1058
1152
|
v = 'untitled' if v == ''
|
|
1059
|
-
|
|
1153
|
+
v.to_s.downcase.to_sym
|
|
1060
1154
|
end
|
|
1061
1155
|
|
|
1062
1156
|
# This is run inside .all, after all of the records have been loaded
|