sequel 5.39.0 → 5.72.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +408 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +59 -27
- data/bin/sequel +11 -3
- data/doc/advanced_associations.rdoc +16 -14
- data/doc/association_basics.rdoc +119 -24
- data/doc/cheat_sheet.rdoc +11 -3
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +13 -6
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +26 -12
- data/doc/postgresql.rdoc +16 -8
- data/doc/querying.rdoc +5 -3
- data/doc/release_notes/5.40.0.txt +40 -0
- data/doc/release_notes/5.41.0.txt +25 -0
- data/doc/release_notes/5.42.0.txt +136 -0
- data/doc/release_notes/5.43.0.txt +98 -0
- data/doc/release_notes/5.44.0.txt +32 -0
- data/doc/release_notes/5.45.0.txt +34 -0
- data/doc/release_notes/5.46.0.txt +87 -0
- data/doc/release_notes/5.47.0.txt +59 -0
- data/doc/release_notes/5.48.0.txt +14 -0
- data/doc/release_notes/5.49.0.txt +59 -0
- data/doc/release_notes/5.50.0.txt +78 -0
- data/doc/release_notes/5.51.0.txt +47 -0
- data/doc/release_notes/5.52.0.txt +87 -0
- data/doc/release_notes/5.53.0.txt +23 -0
- data/doc/release_notes/5.54.0.txt +27 -0
- data/doc/release_notes/5.55.0.txt +21 -0
- data/doc/release_notes/5.56.0.txt +51 -0
- data/doc/release_notes/5.57.0.txt +23 -0
- data/doc/release_notes/5.58.0.txt +31 -0
- data/doc/release_notes/5.59.0.txt +73 -0
- data/doc/release_notes/5.60.0.txt +22 -0
- data/doc/release_notes/5.61.0.txt +43 -0
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/release_notes/5.63.0.txt +33 -0
- data/doc/release_notes/5.64.0.txt +50 -0
- data/doc/release_notes/5.65.0.txt +21 -0
- data/doc/release_notes/5.66.0.txt +24 -0
- data/doc/release_notes/5.67.0.txt +32 -0
- data/doc/release_notes/5.68.0.txt +61 -0
- data/doc/release_notes/5.69.0.txt +26 -0
- data/doc/release_notes/5.70.0.txt +35 -0
- data/doc/release_notes/5.71.0.txt +21 -0
- data/doc/release_notes/5.72.0.txt +33 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sharding.rdoc +3 -1
- data/doc/sql.rdoc +28 -16
- data/doc/testing.rdoc +22 -11
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/access.rb +1 -1
- data/lib/sequel/adapters/ado.rb +17 -17
- data/lib/sequel/adapters/amalgalite.rb +3 -5
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +8 -0
- data/lib/sequel/adapters/jdbc/h2.rb +60 -10
- data/lib/sequel/adapters/jdbc/hsqldb.rb +6 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +7 -4
- data/lib/sequel/adapters/jdbc.rb +16 -18
- data/lib/sequel/adapters/mysql.rb +92 -67
- data/lib/sequel/adapters/mysql2.rb +54 -49
- data/lib/sequel/adapters/odbc.rb +6 -2
- data/lib/sequel/adapters/oracle.rb +4 -3
- data/lib/sequel/adapters/postgres.rb +83 -40
- data/lib/sequel/adapters/shared/access.rb +11 -1
- data/lib/sequel/adapters/shared/db2.rb +30 -0
- data/lib/sequel/adapters/shared/mssql.rb +90 -9
- data/lib/sequel/adapters/shared/mysql.rb +47 -2
- data/lib/sequel/adapters/shared/oracle.rb +82 -1
- data/lib/sequel/adapters/shared/postgres.rb +496 -178
- data/lib/sequel/adapters/shared/sqlanywhere.rb +11 -1
- data/lib/sequel/adapters/shared/sqlite.rb +116 -11
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +60 -18
- data/lib/sequel/adapters/tinytds.rb +1 -1
- data/lib/sequel/adapters/trilogy.rb +117 -0
- data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
- data/lib/sequel/ast_transformer.rb +6 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -7
- data/lib/sequel/connection_pool/sharded_threaded.rb +16 -11
- data/lib/sequel/connection_pool/sharded_timed_queue.rb +374 -0
- data/lib/sequel/connection_pool/single.rb +6 -8
- data/lib/sequel/connection_pool/threaded.rb +14 -8
- data/lib/sequel/connection_pool/timed_queue.rb +270 -0
- data/lib/sequel/connection_pool.rb +55 -31
- data/lib/sequel/core.rb +28 -18
- data/lib/sequel/database/connecting.rb +27 -3
- data/lib/sequel/database/dataset.rb +16 -6
- data/lib/sequel/database/misc.rb +69 -14
- data/lib/sequel/database/query.rb +73 -2
- data/lib/sequel/database/schema_generator.rb +46 -53
- data/lib/sequel/database/schema_methods.rb +18 -2
- data/lib/sequel/dataset/actions.rb +108 -14
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +42 -0
- data/lib/sequel/dataset/features.rb +20 -0
- data/lib/sequel/dataset/misc.rb +12 -2
- data/lib/sequel/dataset/placeholder_literalizer.rb +20 -9
- data/lib/sequel/dataset/prepared_statements.rb +2 -0
- data/lib/sequel/dataset/query.rb +171 -44
- data/lib/sequel/dataset/sql.rb +182 -47
- data/lib/sequel/dataset.rb +4 -0
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/any_not_empty.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +439 -0
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/blank.rb +8 -0
- data/lib/sequel/extensions/connection_expiration.rb +15 -9
- data/lib/sequel/extensions/connection_validator.rb +16 -11
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +36 -11
- data/lib/sequel/extensions/date_arithmetic.rb +71 -31
- data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
- data/lib/sequel/extensions/datetime_parse_to_time.rb +5 -1
- data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/index_caching.rb +5 -1
- data/lib/sequel/extensions/inflector.rb +9 -1
- data/lib/sequel/extensions/is_distinct_from.rb +141 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -0
- data/lib/sequel/extensions/migration.rb +11 -2
- data/lib/sequel/extensions/named_timezones.rb +26 -6
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +32 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +509 -0
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +110 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -3
- data/lib/sequel/extensions/pg_extended_date_support.rb +38 -27
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +6 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +53 -3
- data/lib/sequel/extensions/pg_inet.rb +10 -11
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +45 -19
- data/lib/sequel/extensions/pg_json.rb +13 -15
- data/lib/sequel/extensions/pg_json_ops.rb +73 -2
- data/lib/sequel/extensions/pg_loose_count.rb +3 -1
- data/lib/sequel/extensions/pg_multirange.rb +367 -0
- data/lib/sequel/extensions/pg_range.rb +11 -24
- data/lib/sequel/extensions/pg_range_ops.rb +37 -9
- data/lib/sequel/extensions/pg_row.rb +21 -19
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/query.rb +2 -0
- data/lib/sequel/extensions/s.rb +2 -1
- data/lib/sequel/extensions/schema_caching.rb +1 -1
- data/lib/sequel/extensions/schema_dumper.rb +45 -11
- data/lib/sequel/extensions/server_block.rb +10 -13
- data/lib/sequel/extensions/set_literalizer.rb +58 -0
- data/lib/sequel/extensions/sql_comments.rb +110 -3
- data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
- data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
- data/lib/sequel/extensions/string_agg.rb +1 -1
- data/lib/sequel/extensions/string_date_time.rb +19 -23
- data/lib/sequel/extensions/symbol_aref.rb +2 -0
- data/lib/sequel/model/associations.rb +345 -101
- data/lib/sequel/model/base.rb +51 -27
- data/lib/sequel/model/dataset_module.rb +3 -0
- data/lib/sequel/model/errors.rb +10 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model/plugins.rb +5 -0
- data/lib/sequel/plugins/association_proxies.rb +2 -0
- data/lib/sequel/plugins/async_thread_pool.rb +39 -0
- data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
- data/lib/sequel/plugins/auto_validations.rb +87 -15
- data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/column_encryption.rb +728 -0
- data/lib/sequel/plugins/composition.rb +10 -4
- data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
- data/lib/sequel/plugins/constraint_validations.rb +10 -6
- data/lib/sequel/plugins/dataset_associations.rb +4 -1
- data/lib/sequel/plugins/defaults_setter.rb +16 -0
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/enum.rb +124 -0
- data/lib/sequel/plugins/finder.rb +4 -2
- data/lib/sequel/plugins/insert_conflict.rb +4 -0
- data/lib/sequel/plugins/instance_specific_default.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +39 -24
- data/lib/sequel/plugins/lazy_attributes.rb +3 -0
- data/lib/sequel/plugins/list.rb +3 -1
- data/lib/sequel/plugins/many_through_many.rb +109 -10
- data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -38
- data/lib/sequel/plugins/nested_attributes.rb +12 -7
- data/lib/sequel/plugins/optimistic_locking.rb +9 -42
- data/lib/sequel/plugins/optimistic_locking_base.rb +55 -0
- data/lib/sequel/plugins/pg_array_associations.rb +56 -38
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +11 -3
- data/lib/sequel/plugins/pg_xmin_optimistic_locking.rb +109 -0
- data/lib/sequel/plugins/prepared_statements.rb +12 -2
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/rcte_tree.rb +27 -19
- data/lib/sequel/plugins/require_valid_schema.rb +67 -0
- data/lib/sequel/plugins/serialization.rb +9 -3
- data/lib/sequel/plugins/serialization_modification_detection.rb +2 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +8 -0
- data/lib/sequel/plugins/sql_comments.rb +189 -0
- data/lib/sequel/plugins/static_cache.rb +39 -1
- data/lib/sequel/plugins/static_cache_cache.rb +5 -1
- data/lib/sequel/plugins/subclasses.rb +28 -11
- data/lib/sequel/plugins/tactical_eager_loading.rb +23 -10
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/unused_associations.rb +521 -0
- data/lib/sequel/plugins/update_or_create.rb +1 -1
- data/lib/sequel/plugins/validate_associated.rb +22 -12
- data/lib/sequel/plugins/validation_helpers.rb +46 -12
- data/lib/sequel/plugins/validation_helpers_generic_type_messages.rb +73 -0
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/sql.rb +1 -1
- data/lib/sequel/timezones.rb +12 -14
- data/lib/sequel/version.rb +1 -1
- metadata +132 -38
data/lib/sequel/dataset/query.rb
CHANGED
@@ -12,6 +12,10 @@ module Sequel
|
|
12
12
|
# in the extension).
|
13
13
|
EXTENSIONS = {}
|
14
14
|
|
15
|
+
# Hash of extension name symbols to modules to load to implement the extension.
|
16
|
+
EXTENSION_MODULES = {}
|
17
|
+
private_constant :EXTENSION_MODULES
|
18
|
+
|
15
19
|
EMPTY_ARRAY = [].freeze
|
16
20
|
|
17
21
|
# The dataset options that require the removal of cached columns if changed.
|
@@ -45,12 +49,8 @@ module Sequel
|
|
45
49
|
METHS
|
46
50
|
|
47
51
|
# Register an extension callback for Dataset objects. ext should be the
|
48
|
-
# extension name symbol, and mod should
|
49
|
-
# dataset
|
50
|
-
# object. If mod is not provided, a block can be provided and is treated
|
51
|
-
# as the mod object.
|
52
|
-
#
|
53
|
-
# If mod is a module, this also registers a Database extension that will
|
52
|
+
# extension name symbol, and mod should be a Module that will be
|
53
|
+
# included in the dataset's class. This also registers a Database extension that will
|
54
54
|
# extend all of the database's datasets.
|
55
55
|
def self.register_extension(ext, mod=nil, &block)
|
56
56
|
if mod
|
@@ -58,14 +58,20 @@ module Sequel
|
|
58
58
|
if mod.is_a?(Module)
|
59
59
|
block = proc{|ds| ds.extend(mod)}
|
60
60
|
Sequel::Database.register_extension(ext){|db| db.extend_datasets(mod)}
|
61
|
+
Sequel.synchronize{EXTENSION_MODULES[ext] = mod}
|
61
62
|
else
|
62
63
|
block = mod
|
63
64
|
end
|
64
65
|
end
|
66
|
+
|
67
|
+
unless mod.is_a?(Module)
|
68
|
+
Sequel::Deprecation.deprecate("Providing a block or non-module to Sequel::Dataset.register_extension is deprecated and support for it will be removed in Sequel 6.")
|
69
|
+
end
|
70
|
+
|
65
71
|
Sequel.synchronize{EXTENSIONS[ext] = block}
|
66
72
|
end
|
67
73
|
|
68
|
-
# On Ruby 2.4+, use clone(:
|
74
|
+
# On Ruby 2.4+, use clone(freeze: false) to create clones, because
|
69
75
|
# we use true freezing in that case, and we need to modify the opts
|
70
76
|
# in the frozen copy.
|
71
77
|
#
|
@@ -116,7 +122,7 @@ module Sequel
|
|
116
122
|
# DB[:items].order(:id).distinct(:id) # SQL: SELECT DISTINCT ON (id) * FROM items ORDER BY id
|
117
123
|
# DB[:items].order(:id).distinct{func(:id)} # SQL: SELECT DISTINCT ON (func(id)) * FROM items ORDER BY id
|
118
124
|
#
|
119
|
-
# There is support for
|
125
|
+
# There is support for emulating the DISTINCT ON support in MySQL, but it
|
120
126
|
# does not support the ORDER of the dataset, and also doesn't work in many
|
121
127
|
# cases if the ONLY_FULL_GROUP_BY sql_mode is used, which is the default on
|
122
128
|
# MySQL 5.7.5+.
|
@@ -195,11 +201,15 @@ module Sequel
|
|
195
201
|
if TRUE_FREEZE
|
196
202
|
# Return a clone of the dataset loaded with the given dataset extensions.
|
197
203
|
# If no related extension file exists or the extension does not have
|
198
|
-
# specific support for Dataset objects, an
|
199
|
-
def extension(*
|
200
|
-
|
201
|
-
|
202
|
-
|
204
|
+
# specific support for Dataset objects, an error will be raised.
|
205
|
+
def extension(*exts)
|
206
|
+
Sequel.extension(*exts)
|
207
|
+
mods = exts.map{|ext| Sequel.synchronize{EXTENSION_MODULES[ext]}}
|
208
|
+
if mods.all?
|
209
|
+
with_extend(*mods)
|
210
|
+
else
|
211
|
+
with_extend(DeprecatedSingletonClassMethods).extension(*exts)
|
212
|
+
end
|
203
213
|
end
|
204
214
|
else
|
205
215
|
# :nocov:
|
@@ -508,6 +518,7 @@ module Sequel
|
|
508
518
|
# argument.
|
509
519
|
# :implicit_qualifier :: The name to use for qualifying implicit conditions. By default,
|
510
520
|
# the last joined or primary table is used.
|
521
|
+
# :join_using :: Force the using of JOIN USING, even if +expr+ is not an array of symbols.
|
511
522
|
# :reset_implicit_qualifier :: Can set to false to ignore this join when future joins determine qualifier
|
512
523
|
# for implicit conditions.
|
513
524
|
# :qualify :: Can be set to false to not do any implicit qualification. Can be set
|
@@ -541,7 +552,7 @@ module Sequel
|
|
541
552
|
return s.join_table(type, ds, expr, options, &block)
|
542
553
|
end
|
543
554
|
|
544
|
-
using_join = expr.is_a?(Array) && !expr.empty? && expr.all?{|x| x.is_a?(Symbol)}
|
555
|
+
using_join = options[:join_using] || (expr.is_a?(Array) && !expr.empty? && expr.all?{|x| x.is_a?(Symbol)})
|
545
556
|
if using_join && !supports_join_using?
|
546
557
|
h = {}
|
547
558
|
expr.each{|e| h[e] = e}
|
@@ -616,7 +627,7 @@ module Sequel
|
|
616
627
|
UNCONDITIONED_JOIN_TYPES.each do |jtype|
|
617
628
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
618
629
|
def #{jtype}_join(table, opts=Sequel::OPTS)
|
619
|
-
raise(Sequel::Error, '#{jtype}_join does not accept join table blocks') if
|
630
|
+
raise(Sequel::Error, '#{jtype}_join does not accept join table blocks') if defined?(yield)
|
620
631
|
raise(Sequel::Error, '#{jtype}_join 2nd argument should be an options hash, not conditions') unless opts.is_a?(Hash)
|
621
632
|
join_table(:#{jtype}, table, nil, opts)
|
622
633
|
end
|
@@ -677,6 +688,56 @@ module Sequel
|
|
677
688
|
clone(:lock => style)
|
678
689
|
end
|
679
690
|
|
691
|
+
# Return a dataset with a WHEN MATCHED THEN DELETE clause added to the
|
692
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
693
|
+
# use it as additional conditions for the match.
|
694
|
+
#
|
695
|
+
# merge_delete
|
696
|
+
# # WHEN MATCHED THEN DELETE
|
697
|
+
#
|
698
|
+
# merge_delete{a > 30}
|
699
|
+
# # WHEN MATCHED AND (a > 30) THEN DELETE
|
700
|
+
def merge_delete(&block)
|
701
|
+
_merge_when(:type=>:delete, &block)
|
702
|
+
end
|
703
|
+
|
704
|
+
# Return a dataset with a WHEN NOT MATCHED THEN INSERT clause added to the
|
705
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
706
|
+
# use it as additional conditions for the match.
|
707
|
+
#
|
708
|
+
# The arguments provided can be any arguments that would be accepted by
|
709
|
+
# #insert.
|
710
|
+
#
|
711
|
+
# merge_insert(i1: :i2, a: Sequel[:b]+11)
|
712
|
+
# # WHEN NOT MATCHED THEN INSERT (i1, a) VALUES (i2, (b + 11))
|
713
|
+
#
|
714
|
+
# merge_insert(:i2, Sequel[:b]+11){a > 30}
|
715
|
+
# # WHEN NOT MATCHED AND (a > 30) THEN INSERT VALUES (i2, (b + 11))
|
716
|
+
def merge_insert(*values, &block)
|
717
|
+
_merge_when(:type=>:insert, :values=>values, &block)
|
718
|
+
end
|
719
|
+
|
720
|
+
# Return a dataset with a WHEN MATCHED THEN UPDATE clause added to the
|
721
|
+
# MERGE statement. If a block is passed, treat it as a virtual row and
|
722
|
+
# use it as additional conditions for the match.
|
723
|
+
#
|
724
|
+
# merge_update(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20)
|
725
|
+
# # WHEN MATCHED THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
|
726
|
+
#
|
727
|
+
# merge_update(i1: :i2){a > 30}
|
728
|
+
# # WHEN MATCHED AND (a > 30) THEN UPDATE SET i1 = i2
|
729
|
+
def merge_update(values, &block)
|
730
|
+
_merge_when(:type=>:update, :values=>values, &block)
|
731
|
+
end
|
732
|
+
|
733
|
+
# Return a dataset with the source and join condition to use for the MERGE statement.
|
734
|
+
#
|
735
|
+
# merge_using(:m2, i1: :i2)
|
736
|
+
# # USING m2 ON (i1 = i2)
|
737
|
+
def merge_using(source, join_condition)
|
738
|
+
clone(:merge_using => [source, join_condition].freeze)
|
739
|
+
end
|
740
|
+
|
680
741
|
# Returns a cloned dataset without a row_proc.
|
681
742
|
#
|
682
743
|
# ds = DB[:items].with_row_proc(:invert.to_proc)
|
@@ -699,7 +760,7 @@ module Sequel
|
|
699
760
|
end
|
700
761
|
|
701
762
|
# Returns a copy of the dataset with a specified order. Can be safely combined with limit.
|
702
|
-
# If you call limit with an offset, it will override
|
763
|
+
# If you call limit with an offset, it will override the offset if you've called
|
703
764
|
# offset first.
|
704
765
|
#
|
705
766
|
# DB[:items].offset(10) # SELECT * FROM items OFFSET 10
|
@@ -736,7 +797,7 @@ module Sequel
|
|
736
797
|
# DB[:items].order(Sequel.lit('a + b')) # SELECT * FROM items ORDER BY a + b
|
737
798
|
# DB[:items].order(Sequel[:a] + :b) # SELECT * FROM items ORDER BY (a + b)
|
738
799
|
# DB[:items].order(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name DESC
|
739
|
-
# DB[:items].order(Sequel.asc(:name, :
|
800
|
+
# DB[:items].order(Sequel.asc(:name, nulls: :last)) # SELECT * FROM items ORDER BY name ASC NULLS LAST
|
740
801
|
# DB[:items].order{sum(name).desc} # SELECT * FROM items ORDER BY sum(name) DESC
|
741
802
|
# DB[:items].order(nil) # SELECT * FROM items
|
742
803
|
def order(*columns, &block)
|
@@ -806,13 +867,13 @@ module Sequel
|
|
806
867
|
# DB[:items].returning(nil) # RETURNING NULL
|
807
868
|
# DB[:items].returning(:id, :name) # RETURNING id, name
|
808
869
|
#
|
809
|
-
# DB[:items].returning.insert(:
|
870
|
+
# DB[:items].returning.insert(a: 1) do |hash|
|
810
871
|
# # hash for each row inserted, with values for all columns
|
811
872
|
# end
|
812
|
-
# DB[:items].returning.update(:
|
873
|
+
# DB[:items].returning.update(a: 1) do |hash|
|
813
874
|
# # hash for each row updated, with values for all columns
|
814
875
|
# end
|
815
|
-
# DB[:items].returning.delete(:
|
876
|
+
# DB[:items].returning.delete(a: 1) do |hash|
|
816
877
|
# # hash for each row deleted, with values for all columns
|
817
878
|
# end
|
818
879
|
def returning(*values)
|
@@ -1051,7 +1112,7 @@ module Sequel
|
|
1051
1112
|
# referenced in window functions. See Sequel::SQL::Window for a list of
|
1052
1113
|
# options that can be passed in. Example:
|
1053
1114
|
#
|
1054
|
-
# DB[:items].window(:w, :
|
1115
|
+
# DB[:items].window(:w, partition: :c1, order: :c2)
|
1055
1116
|
# # SELECT * FROM items WINDOW w AS (PARTITION BY c1 ORDER BY c2)
|
1056
1117
|
def window(name, opts)
|
1057
1118
|
clone(:window=>((@opts[:window]||EMPTY_ARRAY) + [[name, SQL::Window.new(opts)].freeze]).freeze)
|
@@ -1059,13 +1120,12 @@ module Sequel
|
|
1059
1120
|
|
1060
1121
|
# Add a common table expression (CTE) with the given name and a dataset that defines the CTE.
|
1061
1122
|
# A common table expression acts as an inline view for the query.
|
1123
|
+
#
|
1062
1124
|
# Options:
|
1063
1125
|
# :args :: Specify the arguments/columns for the CTE, should be an array of symbols.
|
1064
1126
|
# :recursive :: Specify that this is a recursive CTE
|
1065
|
-
#
|
1066
|
-
# PostgreSQL Specific Options:
|
1067
1127
|
# :materialized :: Set to false to force inlining of the CTE, or true to force not inlining
|
1068
|
-
# the CTE (PostgreSQL 12+).
|
1128
|
+
# the CTE (PostgreSQL 12+/SQLite 3.35+).
|
1069
1129
|
#
|
1070
1130
|
# DB[:items].with(:items, DB[:syx].where(Sequel[:name].like('A%')))
|
1071
1131
|
# # WITH items AS (SELECT * FROM syx WHERE (name LIKE 'A%' ESCAPE '\')) SELECT * FROM items
|
@@ -1081,20 +1141,60 @@ module Sequel
|
|
1081
1141
|
|
1082
1142
|
# Add a recursive common table expression (CTE) with the given name, a dataset that
|
1083
1143
|
# defines the nonrecursive part of the CTE, and a dataset that defines the recursive part
|
1084
|
-
# of the CTE.
|
1144
|
+
# of the CTE.
|
1145
|
+
#
|
1146
|
+
# Options:
|
1085
1147
|
# :args :: Specify the arguments/columns for the CTE, should be an array of symbols.
|
1086
1148
|
# :union_all :: Set to false to use UNION instead of UNION ALL combining the nonrecursive and recursive parts.
|
1087
1149
|
#
|
1150
|
+
# PostgreSQL 14+ Options:
|
1151
|
+
# :cycle :: Stop recursive searching when a cycle is detected. Includes two columns in the
|
1152
|
+
# result of the CTE, a cycle column indicating whether a cycle was detected for
|
1153
|
+
# the current row, and a path column for the path traversed to get to the current
|
1154
|
+
# row. If given, must be a hash with the following keys:
|
1155
|
+
# :columns :: (required) The column or array of columns to use to detect a cycle.
|
1156
|
+
# If the value of these columns match columns already traversed, then
|
1157
|
+
# a cycle is detected, and recursive searching will not traverse beyond
|
1158
|
+
# the cycle (the CTE will include the row where the cycle was detected).
|
1159
|
+
# :cycle_column :: The name of the cycle column in the output, defaults to :is_cycle.
|
1160
|
+
# :cycle_value :: The value of the cycle column in the output if the current row was
|
1161
|
+
# detected as a cycle, defaults to true.
|
1162
|
+
# :noncycle_value :: The value of the cycle column in the output if the current row
|
1163
|
+
# was not detected as a cycle, defaults to false. Only respected
|
1164
|
+
# if :cycle_value is given.
|
1165
|
+
# :path_column :: The name of the path column in the output, defaults to :path.
|
1166
|
+
# :search :: Include an order column in the result of the CTE that allows for breadth or
|
1167
|
+
# depth first searching. If given, must be a hash with the following keys:
|
1168
|
+
# :by :: (required) The column or array of columns to search by.
|
1169
|
+
# :order_column :: The name of the order column in the output, defaults to :ordercol.
|
1170
|
+
# :type :: Set to :breadth to use breadth-first searching (depth-first searching
|
1171
|
+
# is the default).
|
1172
|
+
#
|
1088
1173
|
# DB[:t].with_recursive(:t,
|
1089
1174
|
# DB[:i1].select(:id, :parent_id).where(parent_id: nil),
|
1090
1175
|
# DB[:i1].join(:t, id: :parent_id).select(Sequel[:i1][:id], Sequel[:i1][:parent_id]),
|
1091
|
-
# :
|
1176
|
+
# args: [:id, :parent_id])
|
1092
1177
|
#
|
1093
1178
|
# # WITH RECURSIVE t(id, parent_id) AS (
|
1094
1179
|
# # SELECT id, parent_id FROM i1 WHERE (parent_id IS NULL)
|
1095
1180
|
# # UNION ALL
|
1096
1181
|
# # SELECT i1.id, i1.parent_id FROM i1 INNER JOIN t ON (t.id = i1.parent_id)
|
1097
1182
|
# # ) SELECT * FROM t
|
1183
|
+
#
|
1184
|
+
# DB[:t].with_recursive(:t,
|
1185
|
+
# DB[:i1].where(parent_id: nil),
|
1186
|
+
# DB[:i1].join(:t, id: :parent_id).select_all(:i1),
|
1187
|
+
# search: {by: :id, type: :breadth},
|
1188
|
+
# cycle: {columns: :id, cycle_value: 1, noncycle_value: 2})
|
1189
|
+
#
|
1190
|
+
# # WITH RECURSIVE t AS (
|
1191
|
+
# # SELECT * FROM i1 WHERE (parent_id IS NULL)
|
1192
|
+
# # UNION ALL
|
1193
|
+
# # (SELECT i1.* FROM i1 INNER JOIN t ON (t.id = i1.parent_id))
|
1194
|
+
# # )
|
1195
|
+
# # SEARCH BREADTH FIRST BY id SET ordercol
|
1196
|
+
# # CYCLE id SET is_cycle TO 1 DEFAULT 2 USING path
|
1197
|
+
# # SELECT * FROM t
|
1098
1198
|
def with_recursive(name, nonrecursive, recursive, opts=OPTS)
|
1099
1199
|
raise(Error, 'This dataset does not support common table expressions') unless supports_cte?
|
1100
1200
|
if hoist_cte?(nonrecursive)
|
@@ -1109,16 +1209,27 @@ module Sequel
|
|
1109
1209
|
end
|
1110
1210
|
|
1111
1211
|
if TRUE_FREEZE
|
1112
|
-
#
|
1212
|
+
# Create a subclass of the receiver's class, and include the given modules
|
1213
|
+
# into it. If a block is provided, a DatasetModule is created using the block and
|
1214
|
+
# is included into the subclass. Create an instance of the subclass using the
|
1215
|
+
# same db and opts, so that the returned dataset operates similarly to a clone
|
1216
|
+
# extended with the given modules. This approach is used to avoid singleton
|
1217
|
+
# classes, which significantly improves performance.
|
1218
|
+
#
|
1113
1219
|
# Note that like Object#extend, when multiple modules are provided
|
1114
|
-
# as arguments the
|
1115
|
-
# order. If a block is provided, a DatasetModule is created using the block and
|
1116
|
-
# the clone is extended with that module after any modules given as arguments.
|
1220
|
+
# as arguments the subclass includes the modules in reverse order.
|
1117
1221
|
def with_extend(*mods, &block)
|
1118
|
-
c =
|
1119
|
-
c.
|
1120
|
-
c.
|
1121
|
-
c.freeze
|
1222
|
+
c = Class.new(self.class)
|
1223
|
+
c.include(*mods) unless mods.empty?
|
1224
|
+
c.include(DatasetModule.new(&block)) if block
|
1225
|
+
o = c.freeze.allocate
|
1226
|
+
o.instance_variable_set(:@db, @db)
|
1227
|
+
o.instance_variable_set(:@opts, @opts)
|
1228
|
+
o.instance_variable_set(:@cache, {})
|
1229
|
+
if cols = cache_get(:_columns)
|
1230
|
+
o.send(:columns=, cols)
|
1231
|
+
end
|
1232
|
+
o.freeze
|
1122
1233
|
end
|
1123
1234
|
else
|
1124
1235
|
# :nocov:
|
@@ -1151,7 +1262,7 @@ module Sequel
|
|
1151
1262
|
#
|
1152
1263
|
# You can also provide a method name and arguments to call to get the SQL:
|
1153
1264
|
#
|
1154
|
-
# DB[:items].with_sql(:insert_sql, :
|
1265
|
+
# DB[:items].with_sql(:insert_sql, b: 1) # INSERT INTO items (b) VALUES (1)
|
1155
1266
|
#
|
1156
1267
|
# Note that datasets that specify custom SQL using this method will generally
|
1157
1268
|
# ignore future dataset methods that modify the SQL used, as specifying custom SQL
|
@@ -1225,18 +1336,22 @@ module Sequel
|
|
1225
1336
|
|
1226
1337
|
private
|
1227
1338
|
|
1228
|
-
#
|
1229
|
-
|
1230
|
-
|
1231
|
-
exts
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1339
|
+
# :nocov:
|
1340
|
+
unless TRUE_FREEZE
|
1341
|
+
# Load the extensions into the receiver, without checking if the receiver is frozen.
|
1342
|
+
def _extension!(exts)
|
1343
|
+
Sequel.extension(*exts)
|
1344
|
+
exts.each do |ext|
|
1345
|
+
if pr = Sequel.synchronize{EXTENSIONS[ext]}
|
1346
|
+
pr.call(self)
|
1347
|
+
else
|
1348
|
+
raise(Error, "Extension #{ext} does not have specific support handling individual datasets (try: Sequel.extension #{ext.inspect})")
|
1349
|
+
end
|
1236
1350
|
end
|
1351
|
+
self
|
1237
1352
|
end
|
1238
|
-
self
|
1239
1353
|
end
|
1354
|
+
# :nocov:
|
1240
1355
|
|
1241
1356
|
# If invert is true, invert the condition.
|
1242
1357
|
def _invert_filter(cond, invert)
|
@@ -1247,6 +1362,18 @@ module Sequel
|
|
1247
1362
|
end
|
1248
1363
|
end
|
1249
1364
|
|
1365
|
+
# Append to the current MERGE WHEN clauses.
|
1366
|
+
# Mutates the hash to add the conditions, if a virtual row block is passed.
|
1367
|
+
def _merge_when(hash, &block)
|
1368
|
+
hash[:conditions] = Sequel.virtual_row(&block) if block
|
1369
|
+
|
1370
|
+
if merge_when = @opts[:merge_when]
|
1371
|
+
clone(:merge_when => (merge_when.dup << hash.freeze).freeze)
|
1372
|
+
else
|
1373
|
+
clone(:merge_when => [hash.freeze].freeze)
|
1374
|
+
end
|
1375
|
+
end
|
1376
|
+
|
1250
1377
|
# Add the given filter condition. Arguments:
|
1251
1378
|
# clause :: Symbol or which SQL clause to effect, should be :where or :having
|
1252
1379
|
# cond :: The filter condition to add
|