sequel 5.56.0 → 5.59.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.
@@ -123,6 +123,15 @@
123
123
  # c = Sequel.pg_jsonb_op(:c)
124
124
  # DB[:t].update(c['key1'] => 1.to_json, c['key2'] => "a".to_json)
125
125
  #
126
+ # On PostgreSQL 15+, the <tt>IS [NOT] JSON</tt> operator is supported:
127
+ #
128
+ # j.is_json # j IS JSON
129
+ # j.is_json(type: :object) # j IS JSON OBJECT
130
+ # j.is_json(type: :object, unique: true) # j IS JSON OBJECT WITH UNIQUE
131
+ # j.is_not_json # j IS NOT JSON
132
+ # j.is_json(type: :array) # j IS NOT JSON ARRAY
133
+ # j.is_json(unique: true) # j IS NOT JSON WITH UNIQUE
134
+ #
126
135
  # If you are also using the pg_json extension, you should load it before
127
136
  # loading this extension. Doing so will allow you to use the #op method on
128
137
  # JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
@@ -151,6 +160,18 @@ module Sequel
151
160
  GET_PATH = ["(".freeze, " #> ".freeze, ")".freeze].freeze
152
161
  GET_PATH_TEXT = ["(".freeze, " #>> ".freeze, ")".freeze].freeze
153
162
 
163
+ IS_JSON = ["(".freeze, " IS JSON".freeze, "".freeze, ")".freeze].freeze
164
+ IS_NOT_JSON = ["(".freeze, " IS NOT JSON".freeze, "".freeze, ")".freeze].freeze
165
+ EMPTY_STRING = Sequel::LiteralString.new('').freeze
166
+ WITH_UNIQUE = Sequel::LiteralString.new(' WITH UNIQUE').freeze
167
+ IS_JSON_MAP = {
168
+ nil => EMPTY_STRING,
169
+ :value => Sequel::LiteralString.new(' VALUE').freeze,
170
+ :scalar => Sequel::LiteralString.new(' SCALAR').freeze,
171
+ :object => Sequel::LiteralString.new(' OBJECT').freeze,
172
+ :array => Sequel::LiteralString.new(' ARRAY').freeze
173
+ }.freeze
174
+
154
175
  # Get JSON array element or object field as json. If an array is given,
155
176
  # gets the object at the specified path.
156
177
  #
@@ -233,6 +254,30 @@ module Sequel
233
254
  end
234
255
  end
235
256
 
257
+ # Return whether the json object can be parsed as JSON.
258
+ #
259
+ # Options:
260
+ # :type :: Check whether the json object can be parsed as a specific type
261
+ # of JSON (:value, :scalar, :object, :array).
262
+ # :unique :: Check JSON objects for unique keys.
263
+ #
264
+ # json_op.is_json # json IS JSON
265
+ # json_op.is_json(type: :object) # json IS JSON OBJECT
266
+ # json_op.is_json(unique: true) # json IS JSON WITH UNIQUE
267
+ def is_json(opts=OPTS)
268
+ _is_json(IS_JSON, opts)
269
+ end
270
+
271
+ # Return whether the json object cannot be parsed as JSON. The opposite
272
+ # of #is_json. See #is_json for options.
273
+ #
274
+ # json_op.is_not_json # json IS NOT JSON
275
+ # json_op.is_not_json(type: :object) # json IS NOT JSON OBJECT
276
+ # json_op.is_not_json(unique: true) # json IS NOT JSON WITH UNIQUE
277
+ def is_not_json(opts=OPTS)
278
+ _is_json(IS_NOT_JSON, opts)
279
+ end
280
+
236
281
  # Returns a set of keys AS text in the json object.
237
282
  #
238
283
  # json_op.keys # json_object_keys(json)
@@ -286,6 +331,13 @@ module Sequel
286
331
 
287
332
  private
288
333
 
334
+ # Internals of IS [NOT] JSON support
335
+ def _is_json(lit_array, opts)
336
+ raise Error, "invalid is_json :type option: #{opts[:type].inspect}" unless type = IS_JSON_MAP[opts[:type]]
337
+ unique = opts[:unique] ? WITH_UNIQUE : EMPTY_STRING
338
+ Sequel::SQL::BooleanExpression.new(:NOOP, Sequel::SQL::PlaceholderLiteralString.new(lit_array, [self, type, unique]))
339
+ end
340
+
289
341
  # Return a placeholder literal with the given str and args, wrapped
290
342
  # in an JSONOp or JSONBOp, used by operators that return json or jsonb.
291
343
  def json_op(str, args)
@@ -1717,6 +1717,8 @@ module Sequel
1717
1717
  # :graph_select :: A column or array of columns to select from the associated table
1718
1718
  # when eagerly loading the association via +eager_graph+. Defaults to all
1719
1719
  # columns in the associated table.
1720
+ # :instance_specific :: Marks the association as instance specific. Should be used if the association block
1721
+ # uses instance specific state, or transient state (accessing current date/time, etc.).
1720
1722
  # :limit :: Limit the number of records to the provided value. Use
1721
1723
  # an array with two elements for the value to specify a
1722
1724
  # limit (first element) and an offset (second element).
@@ -1856,6 +1858,16 @@ module Sequel
1856
1858
  # in certain places to disable optimizations.
1857
1859
  opts[:instance_specific] = _association_instance_specific_default(name)
1858
1860
  end
1861
+ if (orig_opts[:instance_specific] || orig_opts[:dataset]) && !opts.has_key?(:allow_eager) && !opts[:eager_loader]
1862
+ # For associations explicitly marked as instance specific, or that use the
1863
+ # :dataset option, where :allow_eager is not set, and no :eager_loader is
1864
+ # provided, disallow eager loading. In these cases, eager loading is
1865
+ # unlikely to work. This is not done for implicit setting of :instance_specific,
1866
+ # because implicit use is done by default for all associations with blocks,
1867
+ # and the vast majority of associations with blocks use the block for filtering
1868
+ # in a manner compatible with eager loading.
1869
+ opts[:allow_eager] = false
1870
+ end
1859
1871
  opts = assoc_class.new.merge!(opts)
1860
1872
 
1861
1873
  if opts[:clone] && !opts.cloneable?(cloned_assoc)
@@ -680,10 +680,11 @@ module Sequel
680
680
 
681
681
  private
682
682
 
683
- # Yield to the passed block and if do_raise is false, swallow all errors other than DatabaseConnectionErrors.
683
+ # Yield to the passed block and if do_raise is false, swallow Sequel::Errors other than DatabaseConnectionError
684
+ # and DatabaseDisconnectError.
684
685
  def check_non_connection_error(do_raise=require_valid_table)
685
686
  db.transaction(:savepoint=>:only){yield}
686
- rescue Sequel::DatabaseConnectionError
687
+ rescue Sequel::DatabaseConnectionError, Sequel::DatabaseDisconnectError
687
688
  raise
688
689
  rescue Sequel::Error
689
690
  raise if do_raise
@@ -693,9 +694,12 @@ module Sequel
693
694
  # this model's dataset.
694
695
  def convert_input_dataset(ds)
695
696
  case ds
696
- when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, LiteralString
697
+ when Symbol, SQL::Identifier, SQL::QualifiedIdentifier
697
698
  self.simple_table = db.literal(ds).freeze
698
699
  ds = db.from(ds)
700
+ when SQL::AliasedExpression, LiteralString
701
+ self.simple_table = nil
702
+ ds = db.from(ds)
699
703
  when Dataset
700
704
  ds = ds.from_self(:alias=>ds.first_source) if ds.joined_dataset?
701
705
 
@@ -784,7 +788,7 @@ module Sequel
784
788
  schema_hash = {}
785
789
  ds_opts = dataset.opts
786
790
  get_columns = proc{check_non_connection_error{columns} || []}
787
- schema_array = check_non_connection_error(false){db.schema(dataset, :reload=>reload)} if db.supports_schema_parsing?
791
+ schema_array = get_db_schema_array(reload) if db.supports_schema_parsing?
788
792
  if schema_array
789
793
  schema_array.each{|k,v| schema_hash[k] = v}
790
794
 
@@ -821,6 +825,12 @@ module Sequel
821
825
  schema_hash
822
826
  end
823
827
 
828
+ # Get the array of schema information for the dataset. Returns nil if
829
+ # the schema information cannot be determined.
830
+ def get_db_schema_array(reload)
831
+ check_non_connection_error(false){db.schema(dataset, :reload=>reload)}
832
+ end
833
+
824
834
  # Uncached version of setter_methods, to be overridden by plugins
825
835
  # that want to modify the methods used.
826
836
  def get_setter_methods
@@ -22,6 +22,10 @@ module Sequel
22
22
  # for that album. See the PostgreSQL and SQLite adapter documention for
23
23
  # the options you can pass to the insert_conflict method.
24
24
  #
25
+ # You should not attempt to use this plugin to ignore conflicts when
26
+ # inserting, you should only use it to turn insert conflicts into updates.
27
+ # Any usage to ignore conflicts is not recommended or supported.
28
+ #
25
29
  # Usage:
26
30
  #
27
31
  # # Make all model subclasses support insert_conflict
@@ -33,7 +33,9 @@ module Sequel
33
33
  # You can provide a <tt>:scope</tt> option to scope the list. This option
34
34
  # can be a symbol or array of symbols specifying column name(s), or a proc
35
35
  # that accepts a model instance and returns a dataset representing the list
36
- # the object is in.
36
+ # the object is in. You will need to provide a <tt>:scope</tt> option if
37
+ # the model's dataset uses a subquery (such as when using the class_table_inheritance
38
+ # plugin).
37
39
  #
38
40
  # For example, if each item has a +user_id+ field, and you want every user
39
41
  # to have their own list:
@@ -0,0 +1,67 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Sequel
4
+ module Plugins
5
+ # The require_valid_schema plugin makes Sequel raise or warn if attempting
6
+ # to set the dataset of a model class to a simple table, where the database
7
+ # supports schema parsing, but schema parsing does not work for the model's
8
+ # table.
9
+ #
10
+ # The plugin's default behavior requires that all models that select from a
11
+ # single identifier have a valid table schema, if the database supports
12
+ # schema parsing. If the schema cannot be determined for such
13
+ # a model, an error is raised:
14
+ #
15
+ # Sequel::Model.plugin :require_valid_schema
16
+ #
17
+ # If you load the plugin with an argument of :warn, Sequel will warn instead
18
+ # of raising for such tables:
19
+ #
20
+ # Sequel::Model.plugin :require_valid_schema, :warn
21
+ #
22
+ # This can catch bugs where you expect models to have valid schema, but
23
+ # they do not. This setting only affects future attempts to set datasets
24
+ # in the current class and subclasses created in the future.
25
+ #
26
+ # If you load the plugin with an argument of false, it will not require valid schema.
27
+ # This can be used in subclasses where you do not want to require valid schema,
28
+ # but the plugin must be loaded before a dataset with invalid schema is set:
29
+ #
30
+ # Sequel::Model.plugin :require_valid_schema
31
+ # InvalidSchemaAllowed = Class.new(Sequel::Model)
32
+ # InvalidSchemaAllowed.plugin :require_valid_schema, false
33
+ # class MyModel < InvalidSchemaAllowed
34
+ # end
35
+ module RequireValidSchema
36
+ # Modify the current model's dataset selection, if the model
37
+ # has a dataset.
38
+ def self.configure(model, setting=true)
39
+ model.instance_variable_set(:@require_valid_schema, setting)
40
+ end
41
+
42
+ module ClassMethods
43
+ Plugins.inherited_instance_variables(self, :@require_valid_schema=>nil)
44
+
45
+ private
46
+
47
+ # If the schema cannot be determined, the model uses a simple table,
48
+ # require_valid_schema is set, and the database supports schema parsing, raise or
49
+ # warn based on the require_valid_schema setting.
50
+ def get_db_schema_array(reload)
51
+ schema_array = super
52
+
53
+ if !schema_array && simple_table && @require_valid_schema
54
+ message = "Not able to parse schema for model: #{inspect}, table: #{simple_table}"
55
+ if @require_valid_schema == :warn
56
+ warn message
57
+ else
58
+ raise Error, message
59
+ end
60
+ end
61
+
62
+ schema_array
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -109,6 +109,13 @@ module Sequel
109
109
  # to eagerly set the associated objects, and having separate threads
110
110
  # modify the same model instance is not thread-safe.
111
111
  #
112
+ # Because this plugin will automatically use eager loading for
113
+ # performance, it can break code that defines associations that
114
+ # do not support eager loading, without marking that they do not
115
+ # support eager loading via the <tt>allow_eager: false</tt> option.
116
+ # Make sure to set <tt>allow_eager: false</tt> on any association
117
+ # used with this plugin if the association doesn't support eager loading.
118
+ #
112
119
  # Usage:
113
120
  #
114
121
  # # Make all model subclass instances use tactical eager loading (called before loading subclasses)
@@ -6,7 +6,7 @@ module Sequel
6
6
 
7
7
  # The minor version of Sequel. Bumped for every non-patch level
8
8
  # release, generally around once a month.
9
- MINOR = 56
9
+ MINOR = 59
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.56.0
4
+ version: 5.59.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-01 00:00:00.000000000 Z
11
+ date: 2022-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: minitest-shared_description
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: tzinfo
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -201,6 +187,9 @@ extra_rdoc_files:
201
187
  - doc/release_notes/5.54.0.txt
202
188
  - doc/release_notes/5.55.0.txt
203
189
  - doc/release_notes/5.56.0.txt
190
+ - doc/release_notes/5.57.0.txt
191
+ - doc/release_notes/5.58.0.txt
192
+ - doc/release_notes/5.59.0.txt
204
193
  - doc/release_notes/5.6.0.txt
205
194
  - doc/release_notes/5.7.0.txt
206
195
  - doc/release_notes/5.8.0.txt
@@ -285,6 +274,9 @@ files:
285
274
  - doc/release_notes/5.54.0.txt
286
275
  - doc/release_notes/5.55.0.txt
287
276
  - doc/release_notes/5.56.0.txt
277
+ - doc/release_notes/5.57.0.txt
278
+ - doc/release_notes/5.58.0.txt
279
+ - doc/release_notes/5.59.0.txt
288
280
  - doc/release_notes/5.6.0.txt
289
281
  - doc/release_notes/5.7.0.txt
290
282
  - doc/release_notes/5.8.0.txt
@@ -414,6 +406,7 @@ files:
414
406
  - lib/sequel/extensions/index_caching.rb
415
407
  - lib/sequel/extensions/inflector.rb
416
408
  - lib/sequel/extensions/integer64.rb
409
+ - lib/sequel/extensions/is_distinct_from.rb
417
410
  - lib/sequel/extensions/looser_typecasting.rb
418
411
  - lib/sequel/extensions/migration.rb
419
412
  - lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb
@@ -536,6 +529,7 @@ files:
536
529
  - lib/sequel/plugins/prepared_statements.rb
537
530
  - lib/sequel/plugins/prepared_statements_safe.rb
538
531
  - lib/sequel/plugins/rcte_tree.rb
532
+ - lib/sequel/plugins/require_valid_schema.rb
539
533
  - lib/sequel/plugins/serialization.rb
540
534
  - lib/sequel/plugins/serialization_modification_detection.rb
541
535
  - lib/sequel/plugins/sharding.rb