sequel 5.85.0 → 5.93.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/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +1 -0
- data/lib/sequel/adapters/jdbc/db2.rb +2 -2
- data/lib/sequel/adapters/jdbc/derby.rb +2 -2
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
- data/lib/sequel/adapters/jdbc/jtds.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +5 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +5 -5
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +6 -6
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -2
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +8 -8
- data/lib/sequel/adapters/mysql2.rb +8 -1
- data/lib/sequel/adapters/oracle.rb +16 -0
- data/lib/sequel/adapters/shared/access.rb +1 -0
- data/lib/sequel/adapters/shared/mssql.rb +4 -3
- data/lib/sequel/adapters/shared/mysql.rb +8 -4
- data/lib/sequel/adapters/shared/oracle.rb +1 -0
- data/lib/sequel/adapters/shared/postgres.rb +140 -9
- data/lib/sequel/adapters/sqlite.rb +4 -0
- data/lib/sequel/adapters/trilogy.rb +1 -2
- data/lib/sequel/core.rb +15 -0
- data/lib/sequel/database/dataset_defaults.rb +3 -3
- data/lib/sequel/database/misc.rb +17 -4
- data/lib/sequel/database/query.rb +11 -11
- data/lib/sequel/database/schema_generator.rb +8 -0
- data/lib/sequel/dataset/deprecated_singleton_class_methods.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +70 -25
- data/lib/sequel/dataset/query.rb +9 -5
- data/lib/sequel/dataset/sql.rb +19 -9
- data/lib/sequel/extensions/connection_validator.rb +15 -10
- data/lib/sequel/extensions/migration.rb +23 -3
- data/lib/sequel/extensions/null_dataset.rb +2 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +6 -1
- data/lib/sequel/extensions/pg_auto_parameterize_in_array.rb +93 -10
- data/lib/sequel/extensions/pg_enum.rb +3 -3
- data/lib/sequel/extensions/pg_row.rb +3 -1
- data/lib/sequel/extensions/pg_schema_caching.rb +90 -0
- data/lib/sequel/extensions/query_blocker.rb +172 -0
- data/lib/sequel/extensions/schema_caching.rb +24 -9
- data/lib/sequel/extensions/schema_dumper.rb +16 -4
- data/lib/sequel/extensions/sqlite_json_ops.rb +1 -1
- data/lib/sequel/extensions/string_agg.rb +2 -2
- data/lib/sequel/extensions/virtual_row_method_block.rb +1 -0
- data/lib/sequel/model/associations.rb +28 -3
- data/lib/sequel/model/base.rb +67 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/enum.rb +1 -1
- data/lib/sequel/plugins/forbid_lazy_load.rb +14 -1
- data/lib/sequel/plugins/inspect_pk.rb +44 -0
- data/lib/sequel/plugins/instance_filters.rb +4 -1
- data/lib/sequel/plugins/inverted_subsets.rb +1 -0
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +10 -5
- data/lib/sequel/plugins/paged_operations.rb +5 -2
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +6 -1
- data/lib/sequel/plugins/pg_auto_validate_enums.rb +88 -0
- data/lib/sequel/plugins/pg_eager_any_typed_array.rb +95 -0
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +11 -5
- data/lib/sequel/plugins/sql_comments.rb +7 -2
- data/lib/sequel/plugins/static_cache_cache.rb +50 -13
- data/lib/sequel/plugins/subset_conditions.rb +85 -5
- data/lib/sequel/plugins/subset_static_cache.rb +263 -0
- data/lib/sequel/sql.rb +15 -6
- data/lib/sequel/version.rb +1 -1
- metadata +9 -6
@@ -51,14 +51,7 @@ module Sequel
|
|
51
51
|
module SchemaCaching
|
52
52
|
# Dump the cached schema to the filename given in Marshal format.
|
53
53
|
def dump_schema_cache(file)
|
54
|
-
sch =
|
55
|
-
@schemas.sort.each do |k,v|
|
56
|
-
sch[k] = v.map do |c, h|
|
57
|
-
h = Hash[h]
|
58
|
-
h.delete(:callable_default)
|
59
|
-
[c, h]
|
60
|
-
end
|
61
|
-
end
|
54
|
+
sch = dumpable_schema_cache
|
62
55
|
File.open(file, 'wb'){|f| f.write(Marshal.dump(sch))}
|
63
56
|
nil
|
64
57
|
end
|
@@ -72,7 +65,7 @@ module Sequel
|
|
72
65
|
# Replace the schema cache with the data from the given file, which
|
73
66
|
# should be in Marshal format.
|
74
67
|
def load_schema_cache(file)
|
75
|
-
@schemas =
|
68
|
+
@schemas = load_schema_cache_file(file)
|
76
69
|
@schemas.each_value{|v| schema_post_process(v)}
|
77
70
|
nil
|
78
71
|
end
|
@@ -82,6 +75,28 @@ module Sequel
|
|
82
75
|
def load_schema_cache?(file)
|
83
76
|
load_schema_cache(file) if File.exist?(file)
|
84
77
|
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Return the deserialized schema cache file.
|
82
|
+
def load_schema_cache_file(file)
|
83
|
+
Marshal.load(File.read(file))
|
84
|
+
end
|
85
|
+
|
86
|
+
# A dumpable version of the schema cache.
|
87
|
+
def dumpable_schema_cache
|
88
|
+
sch = {}
|
89
|
+
|
90
|
+
@schemas.sort.each do |k,v|
|
91
|
+
sch[k] = v.map do |c, h|
|
92
|
+
h = Hash[h]
|
93
|
+
h.delete(:callable_default)
|
94
|
+
[c, h]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
sch
|
99
|
+
end
|
85
100
|
end
|
86
101
|
|
87
102
|
Database.register_extension(:schema_caching, SchemaCaching)
|
@@ -27,6 +27,11 @@ Sequel.extension :eval_inspect
|
|
27
27
|
|
28
28
|
module Sequel
|
29
29
|
module SchemaDumper
|
30
|
+
# :nocov:
|
31
|
+
IGNORE_INDEX_ERRORS_KEY = RUBY_VERSION >= '3.4' ? 'ignore_index_errors: ' : ':ignore_index_errors=>'
|
32
|
+
# :nocov:
|
33
|
+
private_constant :IGNORE_INDEX_ERRORS_KEY
|
34
|
+
|
30
35
|
# Convert the column schema information to a hash of column options, one of which must
|
31
36
|
# be :type. The other options added should modify that type (e.g. :size). If a
|
32
37
|
# database type is not recognized, return it as a String type.
|
@@ -161,7 +166,7 @@ END_MIG
|
|
161
166
|
def dump_table_schema(table, options=OPTS)
|
162
167
|
gen = dump_table_generator(table, options)
|
163
168
|
commands = [gen.dump_columns, gen.dump_constraints, gen.dump_indexes].reject{|x| x == ''}.join("\n\n")
|
164
|
-
"create_table(#{table.inspect}#{
|
169
|
+
"create_table(#{table.inspect}#{", #{IGNORE_INDEX_ERRORS_KEY}true" if !options[:same_db] && options[:indexes] != false && !gen.indexes.empty?}) do\n#{commands.gsub(/^/, ' ')}\nend"
|
165
170
|
end
|
166
171
|
|
167
172
|
private
|
@@ -252,7 +257,7 @@ END_MIG
|
|
252
257
|
gen.foreign_key(name, table, col_opts)
|
253
258
|
else
|
254
259
|
gen.column(name, type, col_opts)
|
255
|
-
if [Integer, :Bignum, Float, BigDecimal].include?(type) && schema[:db_type] =~ / unsigned\z/
|
260
|
+
if [Integer, :Bignum, Float, BigDecimal].include?(type) && schema[:db_type] =~ / unsigned\z/i
|
256
261
|
gen.check(Sequel::SQL::Identifier.new(name) >= 0)
|
257
262
|
end
|
258
263
|
end
|
@@ -425,6 +430,13 @@ END_MIG
|
|
425
430
|
|
426
431
|
module Schema
|
427
432
|
class CreateTableGenerator
|
433
|
+
# :nocov:
|
434
|
+
DEFAULT_KEY = RUBY_VERSION >= '3.4' ? 'default: ' : ':default=>'
|
435
|
+
IGNORE_ERRORS_KEY = RUBY_VERSION >= '3.4' ? 'ignore_errors: ' : ':ignore_errors=>'
|
436
|
+
# :nocov:
|
437
|
+
private_constant :DEFAULT_KEY
|
438
|
+
private_constant :IGNORE_ERRORS_KEY
|
439
|
+
|
428
440
|
# Dump this generator's columns to a string that could be evaled inside
|
429
441
|
# another instance to represent the same columns
|
430
442
|
def dump_columns
|
@@ -508,7 +520,7 @@ END_MIG
|
|
508
520
|
c = c.dup
|
509
521
|
cols = c.delete(:columns)
|
510
522
|
if table = options[:add_index] || options[:drop_index]
|
511
|
-
"#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{
|
523
|
+
"#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{", #{IGNORE_ERRORS_KEY}true" if options[:ignore_errors]}#{opts_inspect(c)}"
|
512
524
|
else
|
513
525
|
"index #{cols.inspect}#{opts_inspect(c)}"
|
514
526
|
end
|
@@ -526,7 +538,7 @@ END_MIG
|
|
526
538
|
if opts[:default]
|
527
539
|
opts = opts.dup
|
528
540
|
de = Sequel.eval_inspect(opts.delete(:default))
|
529
|
-
",
|
541
|
+
", #{DEFAULT_KEY}#{de}#{", #{opts.inspect[1...-1]}" if opts.length > 0}"
|
530
542
|
else
|
531
543
|
", #{opts.inspect[1...-1]}" if opts.length > 0
|
532
544
|
end
|
@@ -35,7 +35,7 @@
|
|
35
35
|
#
|
36
36
|
# j[1] # (json_column ->> 1)
|
37
37
|
# j.get(1) # (json_column ->> 1)
|
38
|
-
# j.
|
38
|
+
# j.get_json(1) # (json_column -> 1)
|
39
39
|
# j.extract('$.a') # json_extract(json_column, '$.a')
|
40
40
|
# jb.extract('$.a') # jsonb_extract(jsonb_column, '$.a')
|
41
41
|
#
|
@@ -173,7 +173,7 @@ module Sequel
|
|
173
173
|
# Return a modified StringAgg that uses distinct expressions
|
174
174
|
def distinct
|
175
175
|
self.class.new(@expr, @separator) do |sa|
|
176
|
-
sa.instance_variable_set(:@order_expr, @order_expr)
|
176
|
+
sa.instance_variable_set(:@order_expr, @order_expr)
|
177
177
|
sa.instance_variable_set(:@distinct, true)
|
178
178
|
end
|
179
179
|
end
|
@@ -181,8 +181,8 @@ module Sequel
|
|
181
181
|
# Return a modified StringAgg with the given order
|
182
182
|
def order(*o)
|
183
183
|
self.class.new(@expr, @separator) do |sa|
|
184
|
-
sa.instance_variable_set(:@distinct, @distinct) if @distinct
|
185
184
|
sa.instance_variable_set(:@order_expr, o.empty? ? nil : o.freeze)
|
185
|
+
sa.instance_variable_set(:@distinct, @distinct)
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
@@ -14,6 +14,7 @@ module Sequel
|
|
14
14
|
module SQL
|
15
15
|
class VirtualRow < BasicObject
|
16
16
|
include(Module.new do
|
17
|
+
Sequel.set_temp_name(self){"Sequel::SQL:VirtualRow::_MethodBlockMethodMissing"}
|
17
18
|
# Handle blocks passed to methods and change the behavior.
|
18
19
|
def method_missing(m, *args, &block)
|
19
20
|
if block
|
@@ -414,6 +414,12 @@ module Sequel
|
|
414
414
|
false
|
415
415
|
end
|
416
416
|
|
417
|
+
# Hash value for the association reflection. This is precomputed to avoid
|
418
|
+
# concurrency issues at runtime.
|
419
|
+
def hash
|
420
|
+
self[:_hash]
|
421
|
+
end
|
422
|
+
|
417
423
|
# Initialize the associations cache for the current association for the given objects.
|
418
424
|
def initialize_association_cache(objects)
|
419
425
|
name = self[:name]
|
@@ -693,6 +699,9 @@ module Sequel
|
|
693
699
|
|
694
700
|
# The predicate condition to use for the eager_loader.
|
695
701
|
def eager_loading_predicate_condition(keys)
|
702
|
+
if transform = self[:eager_loading_predicate_transform]
|
703
|
+
keys = transform.call(keys, self)
|
704
|
+
end
|
696
705
|
{predicate_key=>keys}
|
697
706
|
end
|
698
707
|
|
@@ -759,7 +768,15 @@ module Sequel
|
|
759
768
|
def placeholder_eager_loader
|
760
769
|
cached_fetch(:placeholder_eager_loader) do
|
761
770
|
eager_loading_dataset.placeholder_literalizer_loader do |pl, ds|
|
762
|
-
|
771
|
+
arg = pl.arg
|
772
|
+
|
773
|
+
if transform = self[:eager_loading_predicate_transform]
|
774
|
+
arg = arg.transform do |v|
|
775
|
+
transform.call(v, self)
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
apply_eager_limit_strategy(ds.where(predicate_key=>arg), eager_limit_strategy)
|
763
780
|
end
|
764
781
|
end
|
765
782
|
end
|
@@ -1707,6 +1724,9 @@ module Sequel
|
|
1707
1724
|
# record should be populated.
|
1708
1725
|
# :eager_loader_key :: A symbol for the key column to use to populate the key_hash
|
1709
1726
|
# for the eager loader. Can be set to nil to not populate the key_hash.
|
1727
|
+
# :eager_loading_predicate_transform :: A callable object with which to transform the predicate key values used
|
1728
|
+
# when eager loading. Called with two arguments, the array of predicate key
|
1729
|
+
# values, and a the reflection for the association being eager loaded.
|
1710
1730
|
# :extend :: A module or array of modules to extend the dataset with.
|
1711
1731
|
# :filter_limit_strategy :: Determines the strategy used for enforcing limits and offsets when filtering by
|
1712
1732
|
# limited associations. Possible options are :window_function, :distinct_on, or
|
@@ -1769,6 +1789,9 @@ module Sequel
|
|
1769
1789
|
# Set to nil to not define a setter method for the association.
|
1770
1790
|
# :subqueries_per_union :: The number of subqueries to use in each UNION query, for eager
|
1771
1791
|
# loading limited associations using the default :union strategy.
|
1792
|
+
# :use_placeholder_loader :: Whether to use a placeholder loader when eager loading the
|
1793
|
+
# association. Can be set to false to disable the use of a placeholder
|
1794
|
+
# loader if one would be used by default.
|
1772
1795
|
# :validate :: Set to false to not validate when implicitly saving any associated object.
|
1773
1796
|
# === :many_to_one
|
1774
1797
|
# :key :: foreign key in current model's table that references
|
@@ -1891,7 +1914,7 @@ module Sequel
|
|
1891
1914
|
raise(Error, "cannot clone an association to an association of different type (association #{name} with type #{type} cloning #{opts[:clone]} with type #{cloned_assoc[:type]})")
|
1892
1915
|
end
|
1893
1916
|
|
1894
|
-
opts[:use_placeholder_loader] = !opts[:instance_specific] && !opts[:eager_graph]
|
1917
|
+
opts[:use_placeholder_loader] = !opts[:instance_specific] && !opts[:eager_graph] unless opts.include?(:use_placeholder_loader)
|
1895
1918
|
opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
|
1896
1919
|
opts[:graph_join_type] ||= :left_outer
|
1897
1920
|
opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
|
@@ -1914,6 +1937,8 @@ module Sequel
|
|
1914
1937
|
# Remove :class entry if it exists and is nil, to work with cached_fetch
|
1915
1938
|
opts.delete(:class) unless opts[:class]
|
1916
1939
|
|
1940
|
+
opts[:_hash] = [self, name].hash
|
1941
|
+
|
1917
1942
|
def_association(opts)
|
1918
1943
|
|
1919
1944
|
orig_opts.delete(:clone)
|
@@ -3591,7 +3616,7 @@ module Sequel
|
|
3591
3616
|
|
3592
3617
|
# Prepare a hash loaders and eager options which will be used to implement the eager loading.
|
3593
3618
|
def prepare_eager_load(a, reflections, eager_assoc)
|
3594
|
-
eager_load_data = {}
|
3619
|
+
eager_load_data = {}.compare_by_identity
|
3595
3620
|
|
3596
3621
|
# Key is foreign/primary key name symbol.
|
3597
3622
|
# Value is hash with keys being foreign/primary key values (generally integers)
|
data/lib/sequel/model/base.rb
CHANGED
@@ -87,7 +87,7 @@ module Sequel
|
|
87
87
|
attr_reader :simple_pk
|
88
88
|
|
89
89
|
# Should be the literal table name if this Model's dataset is a simple table (no select, order, join, etc.),
|
90
|
-
# or nil otherwise. This and simple_pk are used for an optimization in Model
|
90
|
+
# or nil otherwise. This and simple_pk are used for an optimization in Model[].
|
91
91
|
attr_reader :simple_table
|
92
92
|
|
93
93
|
# Whether mass assigning via .create/.new/#set/#update should raise an error
|
@@ -184,7 +184,7 @@ module Sequel
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
-
klass = Class.new(self)
|
187
|
+
klass = Sequel.set_temp_name(Class.new(self)){"Sequel::_Model(#{source.inspect})"}
|
188
188
|
|
189
189
|
if source.is_a?(::Sequel::Database)
|
190
190
|
klass.db = source
|
@@ -398,7 +398,7 @@ module Sequel
|
|
398
398
|
end
|
399
399
|
|
400
400
|
# Finds a single record according to the supplied filter.
|
401
|
-
# You are encouraged to use Model
|
401
|
+
# You are encouraged to use Model[] or Model.first instead of this method.
|
402
402
|
#
|
403
403
|
# Artist.find(name: 'Bob')
|
404
404
|
# # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
|
@@ -533,10 +533,28 @@ module Sequel
|
|
533
533
|
end
|
534
534
|
end
|
535
535
|
|
536
|
+
# Return a qualified identifier or array of qualified identifiers for
|
537
|
+
# the model's primary key. Uses the given qualifier if provided, or
|
538
|
+
# the table_name otherwise. If the model does not have a primary key,
|
539
|
+
# raises an +Error+.
|
540
|
+
#
|
541
|
+
# Artist.order(Artist.qualified_primary_key)
|
542
|
+
# # SELECT * FROM artists ORDER BY artists.id
|
543
|
+
def qualified_primary_key(qualifier=table_name)
|
544
|
+
case key = @primary_key
|
545
|
+
when Symbol
|
546
|
+
SQL::QualifiedIdentifier.new(qualifier, key)
|
547
|
+
when Array
|
548
|
+
key.map{|k| SQL::QualifiedIdentifier.new(qualifier, k)}
|
549
|
+
else
|
550
|
+
raise(Error, "#{self} does not have a primary key")
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
536
554
|
# Return a hash where the keys are qualified column references. Uses the given
|
537
555
|
# qualifier if provided, or the table_name otherwise. This is useful if you
|
538
556
|
# plan to join other tables to this table and you want the column references
|
539
|
-
# to be qualified.
|
557
|
+
# to be qualified. If the model does not have a primary key, raises an +Error+.
|
540
558
|
#
|
541
559
|
# Artist.where(Artist.qualified_primary_key_hash(1))
|
542
560
|
# # SELECT * FROM artists WHERE (artists.id = 1)
|
@@ -762,22 +780,36 @@ module Sequel
|
|
762
780
|
end
|
763
781
|
end
|
764
782
|
end
|
783
|
+
|
784
|
+
# Module that the class methods that call dataset methods are kept in.
|
785
|
+
# This allows the methods to be overridden and call super with the
|
786
|
+
# default behavior.
|
787
|
+
def dataset_methods_module
|
788
|
+
return @dataset_methods_module if defined?(@dataset_methods_module)
|
789
|
+
mod_name = "#{name}::@dataset_methods_module"
|
790
|
+
Sequel.synchronize{@dataset_methods_module ||= Sequel.set_temp_name(Module.new){mod_name}}
|
791
|
+
extend(@dataset_methods_module)
|
792
|
+
@dataset_methods_module
|
793
|
+
end
|
765
794
|
|
766
|
-
# Define a model method that calls the dataset method with the same name
|
767
|
-
# only used for methods with names that can't be represented directly in
|
768
|
-
# ruby code.
|
795
|
+
# Define a model method that calls the dataset method with the same name.
|
769
796
|
def def_model_dataset_method(meth)
|
770
797
|
return if respond_to?(meth, true)
|
771
798
|
|
799
|
+
mod = dataset_methods_module
|
800
|
+
|
772
801
|
if meth.to_s =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
773
|
-
|
802
|
+
mod.module_eval(<<END, __FILE__, __LINE__ + 1)
|
803
|
+
def #{meth}(*args, &block); dataset.#{meth}(*args, &block) end
|
804
|
+
ruby2_keywords :#{meth} if respond_to?(:ruby2_keywords, true)
|
805
|
+
END
|
774
806
|
else
|
775
|
-
|
807
|
+
mod.send(:define_method, meth){|*args, &block| dataset.public_send(meth, *args, &block)}
|
808
|
+
# :nocov:
|
809
|
+
mod.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
810
|
+
# :nocov:
|
776
811
|
end
|
777
|
-
|
778
|
-
# :nocov:
|
779
|
-
singleton_class.send(:ruby2_keywords, meth) if respond_to?(:ruby2_keywords, true)
|
780
|
-
# :nocov:
|
812
|
+
mod.send(:alias_method, meth, meth)
|
781
813
|
end
|
782
814
|
|
783
815
|
# Get the schema from the database, fall back on checking the columns
|
@@ -943,7 +975,10 @@ module Sequel
|
|
943
975
|
# Module that the class includes that holds methods the class adds for column accessors and
|
944
976
|
# associations so that the methods can be overridden with +super+.
|
945
977
|
def overridable_methods_module
|
946
|
-
|
978
|
+
return @overridable_methods_module if defined?(@overridable_methods_module)
|
979
|
+
mod_name = "#{name}::@overridable_methods_module"
|
980
|
+
Sequel.synchronize{@overridable_methods_module ||= Sequel.set_temp_name(Module.new){mod_name}}
|
981
|
+
include(@overridable_methods_module)
|
947
982
|
@overridable_methods_module
|
948
983
|
end
|
949
984
|
|
@@ -1311,7 +1346,7 @@ module Sequel
|
|
1311
1346
|
# Returns a string representation of the model instance including
|
1312
1347
|
# the class name and values.
|
1313
1348
|
def inspect
|
1314
|
-
"#<#{
|
1349
|
+
"#<#{inspect_prefix} @values=#{inspect_values}>"
|
1315
1350
|
end
|
1316
1351
|
|
1317
1352
|
# Returns the keys in +values+. May not include all column names.
|
@@ -1597,7 +1632,7 @@ module Sequel
|
|
1597
1632
|
@skip_validation_on_next_save = true
|
1598
1633
|
end
|
1599
1634
|
|
1600
|
-
# Returns
|
1635
|
+
# Returns naked dataset that should return only the row related to this instance.
|
1601
1636
|
#
|
1602
1637
|
# Artist[1].this
|
1603
1638
|
# # SELECT * FROM artists WHERE (id = 1) LIMIT 1
|
@@ -1994,7 +2029,12 @@ module Sequel
|
|
1994
2029
|
set(h) unless h.empty?
|
1995
2030
|
end
|
1996
2031
|
|
1997
|
-
# Default
|
2032
|
+
# Default inspect output for the inspect, by default, just showing the class.
|
2033
|
+
def inspect_prefix
|
2034
|
+
model.name
|
2035
|
+
end
|
2036
|
+
|
2037
|
+
# Default inspect output for the values hash, overwrite to change what #inspect displays.
|
1998
2038
|
def inspect_values
|
1999
2039
|
@values.inspect
|
2000
2040
|
end
|
@@ -2238,7 +2278,7 @@ module Sequel
|
|
2238
2278
|
# Return the dataset ordered by the model's primary key. This should not
|
2239
2279
|
# be used if the model does not have a primary key.
|
2240
2280
|
def _force_primary_key_order
|
2241
|
-
cached_dataset(:_pk_order_ds){order(*
|
2281
|
+
cached_dataset(:_pk_order_ds){order(*unambiguous_primary_key)}
|
2242
2282
|
end
|
2243
2283
|
|
2244
2284
|
# If the dataset is not already ordered, and the model has a primary key,
|
@@ -2266,6 +2306,15 @@ module Sequel
|
|
2266
2306
|
end
|
2267
2307
|
end
|
2268
2308
|
|
2309
|
+
# The primary key for the dataset's model, qualified if the dataset is joined.
|
2310
|
+
def unambiguous_primary_key
|
2311
|
+
if joined_dataset?
|
2312
|
+
model.qualified_primary_key
|
2313
|
+
else
|
2314
|
+
model.primary_key
|
2315
|
+
end
|
2316
|
+
end
|
2317
|
+
|
2269
2318
|
def non_sql_option?(key)
|
2270
2319
|
super || key == :model
|
2271
2320
|
end
|
data/lib/sequel/plugins/enum.rb
CHANGED
@@ -39,6 +39,9 @@ module Sequel
|
|
39
39
|
#
|
40
40
|
# Album.first.artist # no error
|
41
41
|
#
|
42
|
+
# This behavior of enabling +forbid_lazy_load+ automatically from dataset
|
43
|
+
# methods can be disabled using the plugin's +:allow_by_default+ option.
|
44
|
+
#
|
42
45
|
# You can allow lazy loading associations for an instance that it
|
43
46
|
# was previously forbidden for:
|
44
47
|
#
|
@@ -98,7 +101,17 @@ module Sequel
|
|
98
101
|
#
|
99
102
|
# # Make the Album class support forbidding lazy load
|
100
103
|
# Album.plugin :forbid_lazy_load
|
104
|
+
#
|
105
|
+
# # Let lazy loading be forbidden by object, but not automatically for any
|
106
|
+
# # object loaded via dataset.
|
107
|
+
# Album.plugin :forbid_lazy_load, allow_by_default: true
|
101
108
|
module ForbidLazyLoad
|
109
|
+
def self.apply(model, opts=OPTS)
|
110
|
+
unless opts[:allow_by_default]
|
111
|
+
model.send(:dataset_extend, ForbidByDefault, :create_class_methods=>false)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
102
115
|
# Error raised when attempting to lazy load an association when
|
103
116
|
# lazy loading has been forbidden.
|
104
117
|
class Error < StandardError
|
@@ -179,7 +192,7 @@ module Sequel
|
|
179
192
|
end
|
180
193
|
end
|
181
194
|
|
182
|
-
module
|
195
|
+
module ForbidByDefault
|
183
196
|
# Mark model instances retrieved in this call as forbidding lazy loading.
|
184
197
|
def each
|
185
198
|
if row_proc
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Plugins
|
5
|
+
# The inspect_pk plugin includes the pk right next to the
|
6
|
+
# model name in inspect, allowing for easily copying and
|
7
|
+
# pasting to retrieve a copy of the object:
|
8
|
+
#
|
9
|
+
# Album.with_pk(1).inspect
|
10
|
+
# # default: #<Album @values={...}>
|
11
|
+
# # with inspect_pk: #<Album[1] @values={...}>
|
12
|
+
#
|
13
|
+
# Usage:
|
14
|
+
#
|
15
|
+
# # Make all model instances include pk in inspect output
|
16
|
+
# Sequel::Model.plugin :inspect_pk
|
17
|
+
#
|
18
|
+
# # Make Album instances include pk in inspect output
|
19
|
+
# Album.plugin :inspect_pk
|
20
|
+
module InspectPk
|
21
|
+
module InstanceMethods
|
22
|
+
private
|
23
|
+
|
24
|
+
# The primary key value to include in the inspect output, if any.
|
25
|
+
# For composite primary keys, this only includes a value if all
|
26
|
+
# fields are present.
|
27
|
+
def inspect_pk
|
28
|
+
if primary_key && (pk = self.pk) && (!(Array === pk) || pk.all?)
|
29
|
+
pk
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Include the instance's primary key in the output.
|
34
|
+
def inspect_prefix
|
35
|
+
if v = inspect_pk
|
36
|
+
"#{super}[#{v.inspect}]"
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -102,7 +102,10 @@ module Sequel
|
|
102
102
|
|
103
103
|
# Apply the instance filters to the given dataset
|
104
104
|
def apply_instance_filters(ds)
|
105
|
-
instance_filters.inject(ds)
|
105
|
+
instance_filters.inject(ds) do |ds1, i|
|
106
|
+
block = i[1]
|
107
|
+
ds1.where(*i[0], &block)
|
108
|
+
end
|
106
109
|
end
|
107
110
|
|
108
111
|
# Clear the instance filters.
|
@@ -32,6 +32,7 @@ module Sequel
|
|
32
32
|
def self.apply(model, &block)
|
33
33
|
model.instance_exec do
|
34
34
|
@dataset_module_class = Class.new(@dataset_module_class) do
|
35
|
+
Sequel.set_temp_name(self){"#{model.name}::@dataset_module_class(InvertedSubsets)"}
|
35
36
|
include DatasetModuleMethods
|
36
37
|
if block
|
37
38
|
define_method(:inverted_subset_name, &block)
|
@@ -64,7 +64,7 @@ module Sequel
|
|
64
64
|
# :dataset :: The base dataset to use for the lazy attribute lookup
|
65
65
|
# :table :: The table name to use to qualify the attribute and primary key columns.
|
66
66
|
def define_lazy_attribute_getter(a, opts=OPTS)
|
67
|
-
include(@lazy_attributes_module ||= Module.new) unless @lazy_attributes_module
|
67
|
+
include(@lazy_attributes_module ||= Sequel.set_temp_name(Module.new){"#{name}::@lazy_attributes_module"}) unless @lazy_attributes_module
|
68
68
|
@lazy_attributes_module.class_eval do
|
69
69
|
define_method(a) do
|
70
70
|
if !values.has_key?(a) && !new?
|
@@ -129,7 +129,7 @@ module Sequel
|
|
129
129
|
#
|
130
130
|
# If a block is provided, it is used to set the :reject_if option.
|
131
131
|
def nested_attributes(*associations, &block)
|
132
|
-
include(@nested_attributes_module ||= Module.new) unless @nested_attributes_module
|
132
|
+
include(@nested_attributes_module ||= Sequel.set_temp_name(Module.new){"#{name}::@nested_attributes_module"}) unless @nested_attributes_module
|
133
133
|
opts = associations.last.is_a?(Hash) ? associations.pop : OPTS
|
134
134
|
reflections = associations.map{|a| association_reflection(a) || raise(Error, "no association named #{a} for #{self}")}
|
135
135
|
reflections.each do |r|
|
@@ -188,11 +188,10 @@ module Sequel
|
|
188
188
|
|
189
189
|
# Create a new associated object with the given attributes, validate
|
190
190
|
# it when the parent is validated, and save it when the object is saved.
|
191
|
-
# Returns the object
|
191
|
+
# Returns the new object.
|
192
192
|
def nested_attributes_create(meta, attributes)
|
193
|
+
obj = nested_attributes_new(meta, attributes)
|
193
194
|
reflection = meta[:reflection]
|
194
|
-
obj = reflection.associated_class.new
|
195
|
-
nested_attributes_set_attributes(meta, obj, attributes)
|
196
195
|
delay_validate_associated_object(reflection, obj)
|
197
196
|
if reflection.returns_array?
|
198
197
|
public_send(reflection[:name]) << obj
|
@@ -254,7 +253,13 @@ module Sequel
|
|
254
253
|
end
|
255
254
|
obj
|
256
255
|
end
|
257
|
-
|
256
|
+
|
257
|
+
# Returns a new object of the associated class with the given attributes set.
|
258
|
+
def nested_attributes_new(meta, attributes)
|
259
|
+
obj = meta[:reflection].associated_class.new
|
260
|
+
nested_attributes_set_attributes(meta, obj, attributes)
|
261
|
+
end
|
262
|
+
|
258
263
|
# Set the fields in the obj based on the association, only allowing
|
259
264
|
# specific :fields if configured.
|
260
265
|
def nested_attributes_set_attributes(meta, obj, attributes)
|
@@ -157,13 +157,16 @@ module Sequel
|
|
157
157
|
raise Error, "the paged_operations plugin is not supported on DB2 when using emulated offsets, set the :offset_strategy Database option to 'limit_offset' or 'offset_fetch'"
|
158
158
|
end
|
159
159
|
|
160
|
-
case pk =
|
160
|
+
case pk = unambiguous_primary_key
|
161
161
|
when Symbol
|
162
162
|
Sequel.identifier(pk)
|
163
163
|
when Array
|
164
164
|
raise Error, "cannot use #{meth} on a model with a composite primary key"
|
165
|
-
|
165
|
+
when nil
|
166
166
|
raise Error, "cannot use #{meth} on a model without a primary key"
|
167
|
+
else
|
168
|
+
# Likely SQL::QualifiedIdentifier, if the dataset is joined.
|
169
|
+
pk
|
167
170
|
end
|
168
171
|
end
|
169
172
|
|
@@ -135,7 +135,12 @@ module Sequel
|
|
135
135
|
raise Error, "No pg_auto_constraint_validations setup" unless file = @pg_auto_constraint_validations_cache_file
|
136
136
|
pg_auto_constraint_validations_cache = {}
|
137
137
|
@pg_auto_constraint_validations_cache.sort.each do |k, v|
|
138
|
-
|
138
|
+
h = {}
|
139
|
+
v.each do |k, entry|
|
140
|
+
entry = Hash[entry.sort] if entry.is_a?(Hash)
|
141
|
+
h[k] = entry
|
142
|
+
end
|
143
|
+
pg_auto_constraint_validations_cache[k] = h
|
139
144
|
end
|
140
145
|
File.open(file, 'wb'){|f| f.write(Marshal.dump(pg_auto_constraint_validations_cache))}
|
141
146
|
nil
|