sequel 5.39.0 → 5.72.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 +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
|