sequel 5.56.0 → 5.59.0

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