sequel 4.41.0 → 4.42.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|