sequel 5.35.0 → 5.40.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +68 -0
  3. data/README.rdoc +2 -2
  4. data/doc/cheat_sheet.rdoc +5 -5
  5. data/doc/code_order.rdoc +0 -12
  6. data/doc/fork_safety.rdoc +84 -0
  7. data/doc/model_plugins.rdoc +1 -1
  8. data/doc/opening_databases.rdoc +5 -1
  9. data/doc/postgresql.rdoc +1 -1
  10. data/doc/querying.rdoc +3 -3
  11. data/doc/release_notes/5.36.0.txt +60 -0
  12. data/doc/release_notes/5.37.0.txt +30 -0
  13. data/doc/release_notes/5.38.0.txt +28 -0
  14. data/doc/release_notes/5.39.0.txt +19 -0
  15. data/doc/release_notes/5.40.0.txt +40 -0
  16. data/doc/transactions.rdoc +0 -8
  17. data/doc/validations.rdoc +1 -1
  18. data/lib/sequel/adapters/jdbc.rb +15 -3
  19. data/lib/sequel/adapters/jdbc/mysql.rb +4 -4
  20. data/lib/sequel/adapters/odbc.rb +4 -6
  21. data/lib/sequel/adapters/shared/mssql.rb +35 -5
  22. data/lib/sequel/adapters/shared/oracle.rb +13 -7
  23. data/lib/sequel/adapters/shared/postgres.rb +40 -2
  24. data/lib/sequel/adapters/shared/sqlite.rb +35 -1
  25. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
  26. data/lib/sequel/core.rb +5 -6
  27. data/lib/sequel/database/connecting.rb +0 -1
  28. data/lib/sequel/database/misc.rb +14 -0
  29. data/lib/sequel/database/schema_generator.rb +6 -0
  30. data/lib/sequel/database/schema_methods.rb +16 -6
  31. data/lib/sequel/database/transactions.rb +2 -2
  32. data/lib/sequel/dataset/actions.rb +10 -6
  33. data/lib/sequel/dataset/features.rb +10 -0
  34. data/lib/sequel/dataset/prepared_statements.rb +2 -0
  35. data/lib/sequel/dataset/sql.rb +32 -10
  36. data/lib/sequel/extensions/blank.rb +6 -0
  37. data/lib/sequel/extensions/date_arithmetic.rb +6 -3
  38. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  39. data/lib/sequel/extensions/inflector.rb +6 -0
  40. data/lib/sequel/extensions/migration.rb +10 -1
  41. data/lib/sequel/extensions/pg_array.rb +1 -0
  42. data/lib/sequel/extensions/pg_interval.rb +22 -6
  43. data/lib/sequel/extensions/pg_json_ops.rb +44 -2
  44. data/lib/sequel/extensions/pg_row.rb +1 -0
  45. data/lib/sequel/extensions/pg_row_ops.rb +24 -0
  46. data/lib/sequel/extensions/query.rb +3 -0
  47. data/lib/sequel/extensions/schema_dumper.rb +3 -3
  48. data/lib/sequel/model.rb +1 -1
  49. data/lib/sequel/model/associations.rb +1 -0
  50. data/lib/sequel/model/base.rb +23 -4
  51. data/lib/sequel/model/plugins.rb +6 -0
  52. data/lib/sequel/plugins/association_proxies.rb +3 -0
  53. data/lib/sequel/plugins/class_table_inheritance.rb +0 -5
  54. data/lib/sequel/plugins/composition.rb +5 -1
  55. data/lib/sequel/plugins/constraint_validations.rb +2 -1
  56. data/lib/sequel/plugins/dataset_associations.rb +4 -1
  57. data/lib/sequel/plugins/dirty.rb +44 -0
  58. data/lib/sequel/plugins/nested_attributes.rb +3 -1
  59. data/lib/sequel/plugins/pg_array_associations.rb +4 -0
  60. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +2 -0
  61. data/lib/sequel/plugins/single_table_inheritance.rb +7 -0
  62. data/lib/sequel/plugins/tree.rb +9 -4
  63. data/lib/sequel/timezones.rb +8 -3
  64. data/lib/sequel/version.rb +1 -1
  65. metadata +33 -21
@@ -240,7 +240,7 @@ module Sequel
240
240
  if supports_create_or_replace_view?
241
241
  options = options.merge(:replace=>true)
242
242
  else
243
- drop_view(name) rescue nil
243
+ swallow_database_error{drop_view(name)}
244
244
  end
245
245
 
246
246
  create_view(name, source, options)
@@ -580,14 +580,14 @@ module Sequel
580
580
  sql << ' NULL'
581
581
  end
582
582
  end
583
-
583
+
584
584
  # Add primary key SQL fragment to column creation SQL.
585
585
  def column_definition_primary_key_sql(sql, column)
586
586
  if column[:primary_key]
587
587
  if name = column[:primary_key_constraint_name]
588
588
  sql << " CONSTRAINT #{quote_identifier(name)}"
589
589
  end
590
- sql << ' PRIMARY KEY'
590
+ sql << " " << primary_key_constraint_sql_fragment(column)
591
591
  constraint_deferrable_sql_append(sql, column[:primary_key_deferrable])
592
592
  end
593
593
  end
@@ -608,7 +608,7 @@ module Sequel
608
608
  if name = column[:unique_constraint_name]
609
609
  sql << " CONSTRAINT #{quote_identifier(name)}"
610
610
  end
611
- sql << ' UNIQUE'
611
+ sql << ' ' << unique_constraint_sql_fragment(column)
612
612
  constraint_deferrable_sql_append(sql, column[:unique_deferrable])
613
613
  end
614
614
  end
@@ -656,11 +656,11 @@ module Sequel
656
656
  check = "(#{check})" unless check[0..0] == '(' && check[-1..-1] == ')'
657
657
  sql << "CHECK #{check}"
658
658
  when :primary_key
659
- sql << "PRIMARY KEY #{literal(constraint[:columns])}"
659
+ sql << "#{primary_key_constraint_sql_fragment(constraint)} #{literal(constraint[:columns])}"
660
660
  when :foreign_key
661
661
  sql << column_references_table_constraint_sql(constraint.merge(:deferrable=>nil))
662
662
  when :unique
663
- sql << "UNIQUE #{literal(constraint[:columns])}"
663
+ sql << "#{unique_constraint_sql_fragment(constraint)} #{literal(constraint[:columns])}"
664
664
  else
665
665
  raise Error, "Invalid constraint type #{constraint[:type]}, should be :check, :primary_key, :foreign_key, or :unique"
666
666
  end
@@ -892,6 +892,11 @@ module Sequel
892
892
  on_delete_clause(action)
893
893
  end
894
894
 
895
+ # Add fragment for primary key specification, separated for easier overridding.
896
+ def primary_key_constraint_sql_fragment(_)
897
+ 'PRIMARY KEY'
898
+ end
899
+
895
900
  # Proxy the quote_schema_table method to the dataset
896
901
  def quote_schema_table(table)
897
902
  schema_utility_dataset.quote_schema_table(table)
@@ -1047,6 +1052,11 @@ module Sequel
1047
1052
  "#{type}#{literal(Array(elements)) if elements}#{' UNSIGNED' if column[:unsigned]}"
1048
1053
  end
1049
1054
 
1055
+ # Add fragment for unique specification, separated for easier overridding.
1056
+ def unique_constraint_sql_fragment(_)
1057
+ 'UNIQUE'
1058
+ end
1059
+
1050
1060
  # Whether clob should be used for String text: true columns.
1051
1061
  def uses_clob_for_text?
1052
1062
  false
@@ -82,7 +82,7 @@ module Sequel
82
82
  # :server :: The server/shard the transaction is being executed on.
83
83
  def rollback_on_exit(opts=OPTS)
84
84
  synchronize(opts[:server]) do |conn|
85
- raise Error, "Cannot call Sequel:: Database#rollback_on_exit! unless inside a transaction" unless h = _trans(conn)
85
+ raise Error, "Cannot call Sequel:: Database#rollback_on_exit unless inside a transaction" unless h = _trans(conn)
86
86
  rollback = !opts[:cancel]
87
87
 
88
88
  if supports_savepoints?
@@ -154,7 +154,7 @@ module Sequel
154
154
  # Note that this should not be used unless the entire transaction
155
155
  # block is idempotent, as otherwise it can cause non-idempotent
156
156
  # behavior to execute multiple times.
157
- # :rollback :: Can the set to :reraise to reraise any Sequel::Rollback exceptions
157
+ # :rollback :: Can be set to :reraise to reraise any Sequel::Rollback exceptions
158
158
  # raised, or :always to always rollback even if no exceptions occur
159
159
  # (useful for testing).
160
160
  # :server :: The server to use for the transaction. Set to :default, :read_only, or
@@ -607,14 +607,16 @@ module Sequel
607
607
  # as_hash, it accepts an optional :hash parameter, into which entries will
608
608
  # be merged.
609
609
  #
610
- # DB[:table].select_hash(:id, :name) # SELECT id, name FROM table
610
+ # DB[:table].select_hash(:id, :name)
611
+ # # SELECT id, name FROM table
611
612
  # # => {1=>'a', 2=>'b', ...}
612
613
  #
613
614
  # You can also provide an array of column names for either the key_column,
614
615
  # the value column, or both:
615
616
  #
616
- # DB[:table].select_hash([:id, :foo], [:name, :bar]) # SELECT * FROM table
617
- # # {[1, 3]=>['a', 'c'], [2, 4]=>['b', 'd'], ...}
617
+ # DB[:table].select_hash([:id, :foo], [:name, :bar])
618
+ # # SELECT id, foo, name, bar FROM table
619
+ # # => {[1, 3]=>['a', 'c'], [2, 4]=>['b', 'd'], ...}
618
620
  #
619
621
  # When using this method, you must be sure that each expression has an alias
620
622
  # that Sequel can determine.
@@ -626,14 +628,16 @@ module Sequel
626
628
  # Similar to to_hash_groups, but only selects the columns given. Like to_hash_groups,
627
629
  # it accepts an optional :hash parameter, into which entries will be merged.
628
630
  #
629
- # DB[:table].select_hash_groups(:name, :id) # SELECT id, name FROM table
631
+ # DB[:table].select_hash_groups(:name, :id)
632
+ # # SELECT id, name FROM table
630
633
  # # => {'a'=>[1, 4, ...], 'b'=>[2, ...], ...}
631
634
  #
632
635
  # You can also provide an array of column names for either the key_column,
633
636
  # the value column, or both:
634
637
  #
635
- # DB[:table].select_hash_groups([:first, :middle], [:last, :id]) # SELECT * FROM table
636
- # # {['a', 'b']=>[['c', 1], ['d', 2], ...], ...}
638
+ # DB[:table].select_hash_groups([:first, :middle], [:last, :id])
639
+ # # SELECT first, middle, last, id FROM table
640
+ # # => {['a', 'b']=>[['c', 1], ['d', 2], ...], ...}
637
641
  #
638
642
  # When using this method, you must be sure that each expression has an alias
639
643
  # that Sequel can determine.
@@ -51,6 +51,11 @@ module Sequel
51
51
  false
52
52
  end
53
53
 
54
+ # Whether deleting from joined datasets is supported, false by default.
55
+ def supports_deleting_joins?
56
+ supports_modifying_joins?
57
+ end
58
+
54
59
  # Whether the database supports derived column lists (e.g.
55
60
  # "table_expr AS table_alias(column_alias1, column_alias2, ...)"), true by
56
61
  # default.
@@ -178,6 +183,11 @@ module Sequel
178
183
  true
179
184
  end
180
185
 
186
+ # Whether updating joined datasets is supported, false by default.
187
+ def supports_updating_joins?
188
+ supports_modifying_joins?
189
+ end
190
+
181
191
  # Whether the dataset supports the WINDOW clause to define windows used by multiple
182
192
  # window functions, false by default.
183
193
  def supports_window_clause?
@@ -201,7 +201,9 @@ module Sequel
201
201
  when :insert_pk
202
202
  fetch_rows(prepared_sql){|r| return r.values.first}
203
203
  when Array
204
+ # :nocov:
204
205
  case prepared_type[0]
206
+ # :nocov:
205
207
  when :map, :as_hash, :to_hash, :to_hash_groups
206
208
  public_send(*prepared_type, &block)
207
209
  end
@@ -22,7 +22,7 @@ module Sequel
22
22
  def insert_sql(*values)
23
23
  return static_sql(@opts[:sql]) if @opts[:sql]
24
24
 
25
- check_modification_allowed!
25
+ check_insert_allowed!
26
26
 
27
27
  columns = []
28
28
 
@@ -172,7 +172,7 @@ module Sequel
172
172
  # than one table.
173
173
  def update_sql(values = OPTS)
174
174
  return static_sql(opts[:sql]) if opts[:sql]
175
- check_modification_allowed!
175
+ check_update_allowed!
176
176
  check_not_limited!(:update)
177
177
 
178
178
  case values
@@ -215,7 +215,7 @@ module Sequel
215
215
  lines << "def #{'_' if priv}#{type}_sql"
216
216
  lines << 'if sql = opts[:sql]; return static_sql(sql) end' unless priv
217
217
  lines << "if sql = cache_get(:_#{type}_sql); return sql end" if cacheable
218
- lines << 'check_modification_allowed!' << 'check_not_limited!(:delete)' if type == :delete
218
+ lines << 'check_delete_allowed!' << 'check_not_limited!(:delete)' if type == :delete
219
219
  lines << 'sql = @opts[:append_sql] || sql_string_origin'
220
220
 
221
221
  if clauses.all?{|c| c.is_a?(Array)}
@@ -918,10 +918,35 @@ module Sequel
918
918
  !@opts[:no_cache_sql] && !cache_get(:_no_cache_sql)
919
919
  end
920
920
 
921
- # Raise an InvalidOperation exception if deletion is not allowed for this dataset.
921
+ # Raise an InvalidOperation exception if modification is not allowed for this dataset.
922
+ # Check whether it is allowed to insert into this dataset.
923
+ # Only for backwards compatibility with older external adapters.
922
924
  def check_modification_allowed!
925
+ # SEQUEL6: Remove
926
+ Sequel::Deprecation.deprecate("Dataset#check_modification_allowed!", "Use check_{insert,delete,update,truncation}_allowed! instead")
927
+ _check_modification_allowed!(supports_modifying_joins?)
928
+ end
929
+
930
+ # Check whether it is allowed to insert into this dataset.
931
+ def check_insert_allowed!
932
+ _check_modification_allowed!(false)
933
+ end
934
+ alias check_truncation_allowed! check_insert_allowed!
935
+
936
+ # Check whether it is allowed to delete from this dataset.
937
+ def check_delete_allowed!
938
+ _check_modification_allowed!(supports_deleting_joins?)
939
+ end
940
+
941
+ # Check whether it is allowed to update this dataset.
942
+ def check_update_allowed!
943
+ _check_modification_allowed!(supports_updating_joins?)
944
+ end
945
+
946
+ # Internals of the check_*_allowed! methods
947
+ def _check_modification_allowed!(modifying_joins_supported)
923
948
  raise(InvalidOperation, "Grouped datasets cannot be modified") if opts[:group]
924
- raise(InvalidOperation, "Joined datasets cannot be modified") if !supports_modifying_joins? && joined_dataset?
949
+ raise(InvalidOperation, "Joined datasets cannot be modified") if !modifying_joins_supported && joined_dataset?
925
950
  end
926
951
 
927
952
  # Raise error if the dataset uses limits or offsets.
@@ -930,11 +955,6 @@ module Sequel
930
955
  raise InvalidOperation, "Dataset##{type} not supported on datasets with limits or offsets" if opts[:limit] || opts[:offset]
931
956
  end
932
957
 
933
- # Alias of check_modification_allowed!
934
- def check_truncation_allowed!
935
- check_modification_allowed!
936
- end
937
-
938
958
  # Append column list to SQL string.
939
959
  # If the column list is empty, a wildcard (*) is appended.
940
960
  def column_list_append(sql, columns)
@@ -971,7 +991,9 @@ module Sequel
971
991
  # operators unsupported by some databases. Used by adapters for databases
972
992
  # that don't support the operators natively.
973
993
  def complex_expression_emulate_append(sql, op, args)
994
+ # :nocov:
974
995
  case op
996
+ # :nocov:
975
997
  when :%
976
998
  complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(:MOD, a, b)}
977
999
  when :>>
@@ -6,6 +6,12 @@
6
6
  #
7
7
  # Sequel.extension :blank
8
8
 
9
+ [FalseClass, Object, NilClass, Numeric, String, TrueClass].each do |klass|
10
+ if klass.method_defined?(:blank?)
11
+ klass.send(:alias_method, :blank?, :blank?)
12
+ end
13
+ end
14
+
9
15
  class FalseClass
10
16
  # false is always blank
11
17
  def blank?
@@ -49,7 +49,10 @@ module Sequel
49
49
  # Options:
50
50
  # :cast :: Cast to the specified type instead of the default if casting
51
51
  def date_sub(expr, interval, opts=OPTS)
52
- interval = if interval.is_a?(Hash)
52
+ if defined?(ActiveSupport::Duration) && interval.is_a?(ActiveSupport::Duration)
53
+ interval = interval.parts
54
+ end
55
+ interval = if interval.is_a?(Enumerable)
53
56
  h = {}
54
57
  interval.each{|k,v| h[k] = -v unless v.nil?}
55
58
  h
@@ -113,12 +116,12 @@ module Sequel
113
116
  end
114
117
  when :mssql, :h2, :access, :sqlanywhere
115
118
  units = case db_type
116
- when :mssql, :sqlanywhere
117
- MSSQL_DURATION_UNITS
118
119
  when :h2
119
120
  H2_DURATION_UNITS
120
121
  when :access
121
122
  ACCESS_DURATION_UNITS
123
+ else
124
+ MSSQL_DURATION_UNITS
122
125
  end
123
126
  each_valid_interval_unit(h, units) do |value, sql_unit|
124
127
  expr = Sequel.function(:DATEADD, sql_unit, value, expr)
@@ -55,6 +55,8 @@ module Sequel
55
55
 
56
56
  module SQL
57
57
  class Expression
58
+ alias inspect inspect
59
+
58
60
  # Attempt to produce a string suitable for eval, such that:
59
61
  #
60
62
  # eval(obj.inspect) == obj
@@ -105,6 +105,12 @@ class String
105
105
  yield Inflections if block_given?
106
106
  Inflections
107
107
  end
108
+
109
+ %w'classify constantize dasherize demodulize foreign_key humanize pluralize singularize tableize underscore'.each do |m|
110
+ if method_defined?(m)
111
+ alias_method(m, m)
112
+ end
113
+ end
108
114
 
109
115
  # By default, camelize converts the string to UpperCamelCase. If the argument to camelize
110
116
  # is set to :lower then camelize produces lowerCamelCase.
@@ -68,6 +68,9 @@ module Sequel
68
68
  # Allow calling private methods for backwards compatibility
69
69
  @db.send(method_sym, *args, &block)
70
70
  end
71
+ # :nocov:
72
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
73
+ # :nocov:
71
74
 
72
75
  # This object responds to all methods the database responds to.
73
76
  def respond_to_missing?(meth, include_private)
@@ -329,7 +332,8 @@ module Sequel
329
332
  # schema_migrations for timestamped migrations). in the database to keep track
330
333
  # of the current migration version. If no migration version is stored in the
331
334
  # database, the version is considered to be 0. If no target version is
332
- # specified, the database is migrated to the latest version available in the
335
+ # specified, or the target version specified is greater than the latest
336
+ # version available, the database is migrated to the latest version available in the
333
337
  # migration directory.
334
338
  #
335
339
  # For example, to migrate the database to the latest version:
@@ -537,6 +541,11 @@ module Sequel
537
541
  end
538
542
 
539
543
  @direction = current < target ? :up : :down
544
+
545
+ if @direction == :down && @current >= @files.length
546
+ raise Migrator::Error, "Missing migration version(s) needed to migrate down to target version (current: #{current}, target: #{target})"
547
+ end
548
+
540
549
  @migrations = get_migrations
541
550
  end
542
551
 
@@ -213,6 +213,7 @@ module Sequel
213
213
  scalar_typecast_method = :"typecast_value_#{opts.fetch(:scalar_typecast, type)}"
214
214
  define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)}
215
215
  private meth
216
+ alias_method(meth, meth)
216
217
  end
217
218
 
218
219
  @schema_type_classes[:"#{type}_array"] = PGArray
@@ -34,6 +34,13 @@
34
34
 
35
35
  require 'active_support/duration'
36
36
 
37
+ # :nocov:
38
+ begin
39
+ require 'active_support/version'
40
+ rescue LoadError
41
+ end
42
+ # :nocov:
43
+
37
44
  module Sequel
38
45
  module Postgres
39
46
  module IntervalDatabaseMethods
@@ -61,34 +68,37 @@ module Sequel
61
68
 
62
69
  # Creates callable objects that convert strings into ActiveSupport::Duration instances.
63
70
  class Parser
71
+ # Whether ActiveSupport::Duration.new takes parts as array instead of hash
72
+ USE_PARTS_ARRAY = !defined?(ActiveSupport::VERSION::STRING) || ActiveSupport::VERSION::STRING < '5.1'
73
+
64
74
  # Parse the interval input string into an ActiveSupport::Duration instance.
65
75
  def call(string)
66
76
  raise(InvalidValue, "invalid or unhandled interval format: #{string.inspect}") unless matches = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d{2,10}):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/.match(string)
67
77
 
68
78
  value = 0
69
- parts = []
79
+ parts = {}
70
80
 
71
81
  if v = matches[1]
72
82
  v = v.to_i
73
83
  value += 31557600 * v
74
- parts << [:years, v]
84
+ parts[:years] = v
75
85
  end
76
86
  if v = matches[2]
77
87
  v = v.to_i
78
88
  value += 2592000 * v
79
- parts << [:months, v]
89
+ parts[:months] = v
80
90
  end
81
91
  if v = matches[3]
82
92
  v = v.to_i
83
93
  value += 86400 * v
84
- parts << [:days, v]
94
+ parts[:days] = v
85
95
  end
86
96
  if matches[5]
87
97
  seconds = matches[5].to_i * 3600 + matches[6].to_i * 60
88
98
  seconds += matches[8] ? matches[7].to_f : matches[7].to_i
89
99
  seconds *= -1 if matches[4] == '-'
90
100
  value += seconds
91
- parts << [:seconds, seconds]
101
+ parts[:seconds] = seconds
92
102
  elsif matches[9] || matches[10] || matches[11]
93
103
  seconds = 0
94
104
  if v = matches[9]
@@ -101,8 +111,14 @@ module Sequel
101
111
  seconds += matches[12] ? v.to_f : v.to_i
102
112
  end
103
113
  value += seconds
104
- parts << [:seconds, seconds]
114
+ parts[:seconds] = seconds
115
+ end
116
+
117
+ # :nocov:
118
+ if USE_PARTS_ARRAY
119
+ parts = parts.to_a
105
120
  end
121
+ # :nocov:
106
122
 
107
123
  ActiveSupport::Duration.new(value, parts)
108
124
  end
@@ -73,7 +73,10 @@
73
73
  # j.pretty # jsonb_pretty(jsonb_column)
74
74
  # j.set(%w'0 a', :h) # jsonb_set(jsonb_column, ARRAY['0','a'], h, true)
75
75
  #
76
- # On PostgreSQL 12+ SQL/JSON functions and operators are supported:
76
+ # j.set_lax(%w'0 a', :h, false, 'raise_exception')
77
+ # # jsonb_set_lax(jsonb_column, ARRAY['0','a'], h, false, 'raise_exception')
78
+ #
79
+ # On PostgreSQL 12+ SQL/JSON path functions and operators are supported:
77
80
  #
78
81
  # j.path_exists('$.foo') # (jsonb_column @? '$.foo')
79
82
  # j.path_match('$.foo') # (jsonb_column @@ '$.foo')
@@ -84,7 +87,15 @@
84
87
  # j.path_query_array('$.foo') # jsonb_path_query_array(jsonb_column, '$.foo')
85
88
  # j.path_query_first('$.foo') # jsonb_path_query_first(jsonb_column, '$.foo')
86
89
  #
87
- # For the PostgreSQL 12+ SQL/JSON functions, one argument is required (+path+) and
90
+ # On PostgreSQL 13+ timezone-aware SQL/JSON path functions and operators are supported:
91
+ #
92
+ # j.path_exists_tz!('$.foo') # jsonb_path_exists_tz(jsonb_column, '$.foo')
93
+ # j.path_match_tz!('$.foo') # jsonb_path_match_tz(jsonb_column, '$.foo')
94
+ # j.path_query_tz('$.foo') # jsonb_path_query_tz(jsonb_column, '$.foo')
95
+ # j.path_query_array_tz('$.foo') # jsonb_path_query_array_tz(jsonb_column, '$.foo')
96
+ # j.path_query_first_tz('$.foo') # jsonb_path_query_first_tz(jsonb_column, '$.foo')
97
+ #
98
+ # For the PostgreSQL 12+ SQL/JSON path functions, one argument is required (+path+) and
88
99
  # two more arguments are optional (+vars+ and +silent+). +path+ specifies the JSON path.
89
100
  # +vars+ specifies a hash or a string in JSON format of named variables to be
90
101
  # substituted in +path+. +silent+ specifies whether errors are suppressed. By default,
@@ -402,6 +413,11 @@ module Sequel
402
413
  Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_exists, path, vars, silent))
403
414
  end
404
415
 
416
+ # The same as #path_exists!, except that timezone-aware conversions are used for date/time values.
417
+ def path_exists_tz!(path, vars=nil, silent=nil)
418
+ Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_exists_tz, path, vars, silent))
419
+ end
420
+
405
421
  # Returns the first item of the result of JSON path predicate check for the json object.
406
422
  # Returns nil if the first item is not true or false.
407
423
  #
@@ -425,6 +441,11 @@ module Sequel
425
441
  Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_match, path, vars, silent))
426
442
  end
427
443
 
444
+ # The same as #path_match!, except that timezone-aware conversions are used for date/time values.
445
+ def path_match_tz!(path, vars=nil, silent=nil)
446
+ Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_match_tz, path, vars, silent))
447
+ end
448
+
428
449
  # Returns a set of all jsonb values specified by the JSON path
429
450
  # for the json object.
430
451
  #
@@ -440,6 +461,11 @@ module Sequel
440
461
  _path_function(:jsonb_path_query, path, vars, silent)
441
462
  end
442
463
 
464
+ # The same as #path_query, except that timezone-aware conversions are used for date/time values.
465
+ def path_query_tz(path, vars=nil, silent=nil)
466
+ _path_function(:jsonb_path_query_tz, path, vars, silent)
467
+ end
468
+
443
469
  # Returns a jsonb array of all values specified by the JSON path
444
470
  # for the json object.
445
471
  #
@@ -455,6 +481,11 @@ module Sequel
455
481
  JSONBOp.new(_path_function(:jsonb_path_query_array, path, vars, silent))
456
482
  end
457
483
 
484
+ # The same as #path_query_array, except that timezone-aware conversions are used for date/time values.
485
+ def path_query_array_tz(path, vars=nil, silent=nil)
486
+ JSONBOp.new(_path_function(:jsonb_path_query_array_tz, path, vars, silent))
487
+ end
488
+
458
489
  # Returns the first item of the result specified by the JSON path
459
490
  # for the json object.
460
491
  #
@@ -470,6 +501,11 @@ module Sequel
470
501
  JSONBOp.new(_path_function(:jsonb_path_query_first, path, vars, silent))
471
502
  end
472
503
 
504
+ # The same as #path_query_first, except that timezone-aware conversions are used for date/time values.
505
+ def path_query_first_tz(path, vars=nil, silent=nil)
506
+ JSONBOp.new(_path_function(:jsonb_path_query_first_tz, path, vars, silent))
507
+ end
508
+
473
509
  # Return the receiver, since it is already a JSONBOp.
474
510
  def pg_jsonb
475
511
  self
@@ -492,6 +528,12 @@ module Sequel
492
528
  self.class.new(function(:set, wrap_input_array(path), wrap_input_jsonb(other), create_missing))
493
529
  end
494
530
 
531
+ # The same as #set, except if +other+ is +nil+, then behaves according to +null_value_treatment+,
532
+ # which can be one of 'raise_exception', 'use_json_null' (default), 'delete_key', or 'return_target'.
533
+ def set_lax(path, other, create_missing=true, null_value_treatment='use_json_null')
534
+ self.class.new(function(:set_lax, wrap_input_array(path), wrap_input_jsonb(other), create_missing, null_value_treatment))
535
+ end
536
+
495
537
  private
496
538
 
497
539
  # Internals of the jsonb SQL/JSON path functions.