sequel 4.26.0 → 4.27.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf4997b7f0149580e9838f7a7c1d0802ce9fdd6b
4
- data.tar.gz: 21d723dcf70b74e58a194e71c0d1fb31a6775917
3
+ metadata.gz: c8e0006e87c72a9cee83298b0fab32a7ccea74ef
4
+ data.tar.gz: 46a222bb7aa35ce30d2a931c56c0cc49d8fd1b3a
5
5
  SHA512:
6
- metadata.gz: 851a0cbbd200cffc7280a35168450fcfdb690af48b21c5adf6864289df9fa8eb2b7e7999b396598d0bf3db371e1e721db896bdb869288aa79b8d5db36467b2ed
7
- data.tar.gz: 806d66ebf5e196040b42bc023dc2ac13a374037df98e419cc1db69bc2a52c10cd4bae8e6e22c79681ed27256fbba81e109d3a0a593ae62831d3f0cd827c6e2f8
6
+ metadata.gz: db00224bfcada026d014fbe777cee84849e8786a33519258197a371e9f48970c8a37a1e45e05462f90e0c9e89fb638dcfd1c5442855f1d6b02e7a79b2a21901d
7
+ data.tar.gz: 79bbb7ad3a536b02bd7242c2fd2b6f08b2772a5b44ba5acdca66224fe93c009e093861ec9e61b877b8349d77ae3d2c5350edcae41cfd6f10827984be0e77ffde
data/CHANGELOG CHANGED
@@ -1,3 +1,33 @@
1
+ === 4.27.0 (2015-10-01)
2
+
3
+ * Don't stub Sequel.synchronize on MRI (YorickPeterse) (#1083)
4
+
5
+ * Make bin/sequel warn if given arguments that it doesn't use (jeremyevans)
6
+
7
+ * Fix the order of referenced composite keys returned by Database#foreign_key_list on PostgreSQL (jeremyevans) (#1081)
8
+
9
+ * Recognize another disconnect error in the jdbc/postgresql adapter (jeremyevans)
10
+
11
+ * In the active model plugin, make Model#persisted? return false if the transaction used for creation is rolled back (jeremyevans) (#1076)
12
+
13
+ * Use primary_key :keep_order option in the schema dumper if the auto incrementing column is not the first column in the table (jeremyevans)
14
+
15
+ * Set :auto_increment option correctly in the schema parser when the auto incrementing column is not the first column in the table (jeremyevans)
16
+
17
+ * Support :keep_order option to primary_key in schema generator, to not automatically make the primary key the first column (jeremyevans)
18
+
19
+ * Add new jsonb/json functions and operators supported in PostgreSQL 9.5+ (jeremyevans)
20
+
21
+ * Add before_after_save plugin, for refreshing created objects and resetting modified flag before calling after_create/update/save hooks (jeremyevans)
22
+
23
+ * Add Dataset#single_record! and #single_value! which don't require cloning the receiver (jeremyevans)
24
+
25
+ * Dataset#with_sql_single_value now works correctly for model datasets (jeremyevans)
26
+
27
+ * Optimize Dataset#single_value and #with_sql_single_value to not create an unnecessary array (jeremyevans)
28
+
29
+ * Make postgres adapter work with postgres-pr 0.7.0 (jeremyevans) (#1074)
30
+
1
31
  === 4.26.0 (2015-09-01)
2
32
 
3
33
  * Make Dataset#== not consider frozen status in determining equality (jeremyevans)
data/bin/sequel CHANGED
@@ -116,6 +116,9 @@ error_proc = lambda do |msg|
116
116
  $stderr.puts(msg)
117
117
  exit 1
118
118
  end
119
+ extra_proc = lambda do
120
+ $stderr.puts("Warning: last #{ARGV.length} arguments ignored") unless ARGV.empty?
121
+ end
119
122
 
120
123
  error_proc["Error: Must specify -m if using -M"] if migrate_ver && !migrate_dir
121
124
  error_proc["Error: Cannot specify #{exclusive_options.map{|v| "-#{v}"}.join(' and ')} together"] if exclusive_options.length > 1
@@ -151,16 +154,19 @@ begin
151
154
  DB = connect_proc[db]
152
155
  load_dirs.each{|d| d.is_a?(Array) ? require(d.first) : Dir["#{d}/**/*.rb"].each{|f| load(f)}}
153
156
  if migrate_dir
157
+ extra_proc.call
154
158
  Sequel.extension :migration, :core_extensions
155
159
  Sequel::Migrator.apply(DB, migrate_dir, migrate_ver)
156
160
  exit
157
161
  end
158
162
  if dump_migration
163
+ extra_proc.call
159
164
  DB.extension :schema_dumper
160
165
  puts DB.dump_schema_migration(:same_db=>dump_migration==:same_db)
161
166
  exit
162
167
  end
163
168
  if dump_schema
169
+ extra_proc.call
164
170
  DB.extension :schema_caching
165
171
  DB.tables.each{|t| DB.schema(Sequel::SQL::Identifier.new(t))}
166
172
  DB.dump_schema_cache(dump_schema)
@@ -172,6 +178,7 @@ begin
172
178
 
173
179
  db2 = ARGV.shift
174
180
  error_proc["Error: Must specify database connection string or path to yaml file as second argument for database you want to copy to"] if db2.nil? || db2.empty?
181
+ extra_proc.call
175
182
  start_time = Time.now
176
183
  TO_DB = connect_proc[db2]
177
184
  same_db = DB.database_type==TO_DB.database_type
@@ -225,6 +232,7 @@ begin
225
232
  exit
226
233
  end
227
234
  if code
235
+ extra_proc.call
228
236
  eval(code)
229
237
  exit
230
238
  end
@@ -309,7 +309,9 @@ The Sequel postgres adapter works with the pg, postgres, and postgres-pr ruby li
309
309
  The pg library is the best supported, as it supports real bound variables and prepared statements.
310
310
  If the pg library is being used, Sequel will also attempt to load the sequel_pg library, which is
311
311
  a C extension that optimizes performance when Sequel is used with pg. All users of Sequel who
312
- use pg are encouraged to install sequel_pg.
312
+ use pg are encouraged to install sequel_pg. For users who want to use postgres-pr to avoid issues
313
+ with C extensions, it is recommended to use jeremyevans-postgres-pr, which fixes many issues in
314
+ the upstream postgres-pr gem, and is regularly tested with Sequel.
313
315
 
314
316
  The following additional options are supported:
315
317
 
data/doc/postgresql.rdoc CHANGED
@@ -185,6 +185,19 @@ When returning is used, instead of returning the number of rows affected (for up
185
185
  or the serial primary key value (for insert), it will return an array of hashes with the
186
186
  returned results.
187
187
 
188
+ === VALUES Support
189
+
190
+ Sequel offers support for the +VALUES+ statement using <tt>Database#values</tt>:
191
+
192
+ DB.values([[1,2],[2,3],[3,4]])
193
+ # VALUES (1, 2), (2, 3), (3, 4)
194
+
195
+ DB.values([[1,2],[2,3],[3,4]]).order(2, 1)
196
+ # VALUES (1, 2), (2, 3), (3, 4) ORDER BY 2, 1
197
+
198
+ DB.values([[1,2],[2,3],[3,4]]).order(2, 1).limit(1,2)
199
+ # VALUES (1, 2), (2, 3), (3, 4) ORDER BY 2, 1 LIMIT 1 OFFSET 2
200
+
188
201
  === INSERT ON CONFLICT Support
189
202
 
190
203
  Starting with PostgreSQL 9.5, you can do an upsert or ignore unique or exclusion constraint
@@ -0,0 +1,78 @@
1
+ = New Features
2
+
3
+ * A before_after_save plugin has been added, which for newly
4
+ created objects refreshes the object before calling after_create,
5
+ and resets the modified flag before calling after_update.
6
+ Previously, these actions were not taken until after after_save
7
+ was called. This will be the default behavior in Sequel 5.
8
+
9
+ * In create_table blocks, primary_key now supports a :keep_order
10
+ option, which will not change the order in which the primary key
11
+ is added. Without this option, Sequel's historical behavior of
12
+ making the primary key column the first column is used.
13
+
14
+ DB.create_table(:foo) do
15
+ Integer :a
16
+ primary_key :b, :keep_order=>true
17
+ end
18
+ # CREATE TABLE foo
19
+ # (a integer, b integer PRIMARY KEY AUTOINCREMENT)
20
+
21
+ The schema dumper now uses this option if necessary, allowing it
22
+ to correctly dump tables where the primary key column is not the
23
+ first column.
24
+
25
+ * Dataset#single_record! and #single_value! have been added. These
26
+ are faster versions of #single_record and #single_value that
27
+ don't require cloning the dataset. If you are sure the dataset
28
+ will only return a single row or a single value, you can use
29
+ these methods for better performance.
30
+
31
+ * The new jsonb and json functions added in PostgreSQL 9.5 are now
32
+ supported by the pg_json_ops extension.
33
+
34
+ Sequel.pg_jsonb_op(:metadata).set(%w'a b', [1,2,3])
35
+ # jsonb_set("metadata", ARRAY['a','b'], '[1,2,3]'::jsonb, true)
36
+
37
+ = Other Improvements
38
+
39
+ * Sequel.synchronize is no longer a stub on MRI. Testing has shown
40
+ that relying on the global interpreter lock to protect
41
+ multi-threaded access to hashes is not safe in all environments,
42
+ so Sequel now uses a mutex on MRI just as it does on other ruby
43
+ interpreters.
44
+
45
+ * Database#schema now sets the :auto_increment option correctly for
46
+ auto incrementing primary keys if they are not the first column
47
+ in the table.
48
+
49
+ * Dataset#single_value and #with_sql_single_value are now slightly
50
+ faster by avoiding an array allocation.
51
+
52
+ * Model datasets can now use #with_sql_single_value and return a
53
+ single value, instead of an array in [:column_name, value] format.
54
+
55
+ * Model#persisted? in the active_model plugin will now return false
56
+ if the transaction that inserts the row for the object is rolled
57
+ back.
58
+
59
+ * bin/sequel now warns if additional arguments are passed that it
60
+ ignores. In Sequel 5, bin/sequel will raise an error in these
61
+ cases.
62
+
63
+ * Database#foreign_key_list on PostgreSQL now returns referenced
64
+ composite keys in the correct order.
65
+
66
+ * The postgres adapter now works with postgres-pr 0.7.0. Note that
67
+ postgres adapter users that want a pure-ruby driver are encouraged
68
+ to use jeremyevans-postgres-pr as that has many additional bugfixes
69
+ and is the version tested with Sequel on a regular basis.
70
+
71
+ * The jdbc/postgresql adapter now recognizes an additional disconnect
72
+ error.
73
+
74
+ = Backwards Compatibility
75
+
76
+ * Users who were relying on #with_sql_single_value returning an array
77
+ instead of a single value for model datasets need to update their
78
+ code.
@@ -4,7 +4,7 @@ Most Sequel usage (and all common Sequel usage) is thread safe by default. Spec
4
4
 
5
5
  == Connection Pool
6
6
 
7
- In order to allow multiple threads to operate on the same database at the same time, Sequel uses a connection pool. The connection pool is designed so that a thread uses a connection for the minimum amount of time, returning the connection to the pool as soon as it is done using the connection. If a thread requests a connection and the pool does not have an available connection, a new connection will be created. If the maximum number of connections in the pool has already been reached, the thread will block (actually busy-wait) until a connection is available or the connection pool timeout has elapsed (in which case a PoolTimeout error will be raised).
7
+ In order to allow multiple threads to operate on the same database at the same time, Sequel uses a connection pool. The connection pool is designed so that a thread uses a connection for the minimum amount of time, returning the connection to the pool as soon as it is done using the connection. If a thread requests a connection and the pool does not have an available connection, a new connection will be created. If the maximum number of connections in the pool has already been reached, the thread will block until a connection is available or the connection pool timeout has elapsed (in which case a PoolTimeout error will be raised).
8
8
 
9
9
  == Exceptions
10
10
 
@@ -135,7 +135,7 @@ module Sequel
135
135
  end
136
136
 
137
137
  def disconnect_error?(exception, opts)
138
- super || exception.message =~ /\AThis connection has been closed\.\z|\AFATAL: terminating connection due to administrator command\z/
138
+ super || exception.message =~ /\A(This connection has been closed\.|FATAL: terminating connection due to administrator command|An I\/O error occurred while sending to the backend\.)\z/
139
139
  end
140
140
 
141
141
  # Use setNull for nil arguments as the default behavior of setString
@@ -2,6 +2,10 @@ Sequel.require 'adapters/shared/postgres'
2
2
 
3
3
  begin
4
4
  require 'pg'
5
+
6
+ # Work around postgres-pr 0.7.0+ which ships with a pg.rb file
7
+ raise LoadError unless defined?(PGconn::CONNECTION_OK)
8
+
5
9
  SEQUEL_POSTGRES_USES_PG = true
6
10
  rescue LoadError => e
7
11
  SEQUEL_POSTGRES_USES_PG = false
@@ -308,7 +308,7 @@ module Sequel
308
308
  ref_ds = base_ds.
309
309
  join(:pg_class___cl2, :oid=>:co__confrelid).
310
310
  join(:pg_attribute___att2, :attrelid=>:oid, :attnum=>SQL::Function.new(:ANY, :co__confkey)).
311
- order(:co__conname, SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(:co__conkey, [x]), x]}, 32, :att2__attnum)).
311
+ order(:co__conname, SQL::CaseExpression.new(range.map{|x| [SQL::Subscript.new(:co__confkey, [x]), x]}, 32, :att2__attnum)).
312
312
  select(:co__conname___name, :cl2__relname___table, :att2__attname___refcolumn)
313
313
 
314
314
  # If a schema is given, we only search in that schema, and the returned :table
data/lib/sequel/core.rb CHANGED
@@ -293,24 +293,14 @@ module Sequel
293
293
  end
294
294
  end
295
295
 
296
- if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
297
- # :nocov:
298
- # Mutex used to protect mutable data structures
299
- @data_mutex = Mutex.new
300
-
301
- # Unless in single threaded mode, protects access to any mutable
302
- # global data structure in Sequel.
303
- # Uses a non-reentrant mutex, so calling code should be careful.
304
- def self.synchronize(&block)
305
- @single_threaded ? yield : @data_mutex.synchronize(&block)
306
- end
307
- # :nocov:
308
- else
309
- # Yield directly to the block. You don't need to synchronize
310
- # access on MRI because the GVL makes certain methods atomic.
311
- def self.synchronize
312
- yield
313
- end
296
+ # Mutex used to protect mutable data structures
297
+ @data_mutex = Mutex.new
298
+
299
+ # Unless in single threaded mode, protects access to any mutable
300
+ # global data structure in Sequel.
301
+ # Uses a non-reentrant mutex, so calling code should be careful.
302
+ def self.synchronize(&block)
303
+ @single_threaded ? yield : @data_mutex.synchronize(&block)
314
304
  end
315
305
 
316
306
  # Uses a transaction on all given databases with the given options. This:
@@ -161,7 +161,7 @@ module Sequel
161
161
 
162
162
  primary_keys = 0
163
163
  auto_increment_set = false
164
- cols.all? do |_,c|
164
+ cols.each do |_,c|
165
165
  auto_increment_set = true if c.has_key?(:auto_increment)
166
166
  primary_keys += 1 if c[:primary_key]
167
167
  end
@@ -236,22 +236,35 @@ module Sequel
236
236
  #
237
237
  # If an array of column symbols is used, you can specify the :name option
238
238
  # to name the constraint.
239
+ #
240
+ # Options:
241
+ # :keep_order :: For non-composite primary keys, respects the existing order of
242
+ # columns, overriding the default behavior of making the primary
243
+ # key the first column.
239
244
  #
240
245
  # Examples:
241
246
  # primary_key(:id)
247
+ # primary_key(:id, Bigint)
248
+ # primary_key(:id, Bigint, :keep_order=>true)
242
249
  # primary_key([:street_number, :house_number], :name=>:some constraint_name)
243
250
  def primary_key(name, *args)
244
251
  return composite_primary_key(name, *args) if name.is_a?(Array)
245
- @primary_key = @db.serial_primary_key_options.merge({:name => name})
252
+ column = @db.serial_primary_key_options.merge({:name => name})
246
253
 
247
254
  if opts = args.pop
248
255
  opts = {:type => opts} unless opts.is_a?(Hash)
249
256
  if type = args.pop
250
- opts.merge!(:type => type)
257
+ opts = opts.merge(:type => type)
251
258
  end
252
- @primary_key.merge!(opts)
259
+ column.merge!(opts)
260
+ end
261
+
262
+ @primary_key = column
263
+ if column[:keep_order]
264
+ columns << column
265
+ else
266
+ columns.unshift(column)
253
267
  end
254
- @primary_key
255
268
  end
256
269
 
257
270
  # The name of the primary key for this generator, if it has a primary key.
@@ -12,7 +12,7 @@ module Sequel
12
12
  << [] all avg count columns columns! delete each
13
13
  empty? fetch_rows first first! get import insert interval last
14
14
  map max min multi_insert paged_each range select_hash select_hash_groups select_map select_order_map
15
- single_record single_value sum to_hash to_hash_groups truncate update
15
+ single_record single_record! single_value single_value! sum to_hash to_hash_groups truncate update
16
16
  METHS
17
17
 
18
18
  # Inserts the given argument into the database. Returns self so it
@@ -637,22 +637,51 @@ module Sequel
637
637
  _select_map(column, true, &block)
638
638
  end
639
639
 
640
- # Returns the first record in the dataset, or nil if the dataset
641
- # has no records. Users should probably use +first+ instead of
642
- # this method.
640
+ # Limits the dataset to one record, and returns the first record in the dataset,
641
+ # or nil if the dataset has no records. Users should probably use +first+ instead of
642
+ # this method. Example:
643
+ #
644
+ # DB[:test].single_record # SELECT * FROM test LIMIT 1
645
+ # # => {:column_name=>'value'}
643
646
  def single_record
644
- clone(:limit=>1).each{|r| return r}
645
- nil
647
+ clone(:limit=>1).single_record!
648
+ end
649
+
650
+ # Returns the first record in dataset, without limiting the dataset. Returns nil if
651
+ # the dataset has no records. Users should probably use +first+ instead of this method.
652
+ # This should only be used if you know the dataset is already limited to a single record.
653
+ # This method may be desirable to use for performance reasons, as it does not clone the
654
+ # receiver. Example:
655
+ #
656
+ # DB[:test].single_record! # SELECT * FROM test
657
+ # # => {:column_name=>'value'}
658
+ def single_record!
659
+ with_sql_first(select_sql)
646
660
  end
647
661
 
648
662
  # Returns the first value of the first record in the dataset.
649
663
  # Returns nil if dataset is empty. Users should generally use
650
- # +get+ instead of this method.
664
+ # +get+ instead of this method. Example:
665
+ #
666
+ # DB[:test].single_value # SELECT * FROM test LIMIT 1
667
+ # # => 'value'
651
668
  def single_value
652
669
  if r = ungraphed.naked.single_record
653
- r.values.first
670
+ r.each{|_, v| return v}
654
671
  end
655
672
  end
673
+
674
+ # Returns the first value of the first record in the dataset, without limiting the dataset.
675
+ # Returns nil if the dataset is empty. Users should generally use +get+ instead of this
676
+ # method. Should not be used on graphed datasets or datasets that have row_procs that
677
+ # don't return hashes. This method may be desirable to use for performance reasons, as
678
+ # it does not clone the receiver.
679
+ #
680
+ # DB[:test].single_value! # SELECT * FROM test
681
+ # # => 'value'
682
+ def single_value!
683
+ with_sql_single_value(select_sql)
684
+ end
656
685
 
657
686
  # Returns the sum for the given column/expression.
658
687
  # Uses a virtual row block if no column is given.
@@ -818,7 +847,7 @@ module Sequel
818
847
  # only a single value. See with_sql_each.
819
848
  def with_sql_single_value(sql)
820
849
  if r = with_sql_first(sql)
821
- r.values.first
850
+ r.each{|_, v| return v}
822
851
  end
823
852
  end
824
853
 
@@ -50,6 +50,7 @@
50
50
  # j.each_text # json_each_text(json_column)
51
51
  # j.keys # json_object_keys(json_column)
52
52
  # j.typeof # json_typeof(json_column)
53
+ # j.strip_nulls # json_strip_nulls(json_column)
53
54
  #
54
55
  # j.populate(:a) # json_populate_record(:a, json_column)
55
56
  # j.populate_set(:a) # json_populate_recordset(:a, json_column)
@@ -58,11 +59,16 @@
58
59
  #
59
60
  # There are additional methods are are only supported on JSONBOp instances:
60
61
  #
61
- # j.contain_all(:a) # (jsonb_column ?& a)
62
- # j.contain_any(:a) # (jsonb_column ?| a)
63
- # j.contains(:h) # (jsonb_column @> h)
64
- # j.contained_by(:h) # (jsonb_column <@ h)
65
- # j.has_key?('a') # (jsonb_column ? 'a')
62
+ # j - 1 # (jsonb_column - 1)
63
+ # j.concat(:h) # (jsonb_column || h)
64
+ # j.contain_all(:a) # (jsonb_column ?& a)
65
+ # j.contain_any(:a) # (jsonb_column ?| a)
66
+ # j.contains(:h) # (jsonb_column @> h)
67
+ # j.contained_by(:h) # (jsonb_column <@ h)
68
+ # j.delete_path(%w'0 a') # (jsonb_column #- ARRAY['0','a'])
69
+ # j.has_key?('a') # (jsonb_column ? 'a')
70
+ # j.pretty # jsonb_pretty(jsonb_column)
71
+ # j.set(%w'0 a', :h) # jsonb_set(jsonb_column, ARRAY['0','a'], h, true)
66
72
  #
67
73
  # If you are also using the pg_json extension, you should load it before
68
74
  # loading this extension. Doing so will allow you to use the #op method on
@@ -192,6 +198,13 @@ module Sequel
192
198
  SQL::Function.new(function_name(:populate_recordset), arg, self)
193
199
  end
194
200
 
201
+ # Returns a json value stripped of all internal null values.
202
+ #
203
+ # json_op.strip_nulls # json_strip_nulls(json)
204
+ def strip_nulls
205
+ self.class.new(function(:strip_nulls))
206
+ end
207
+
195
208
  # Builds arbitrary record from json object. You need to define the
196
209
  # structure of the record using #as on the resulting object:
197
210
  #
@@ -266,12 +279,30 @@ module Sequel
266
279
  #
267
280
  # jsonb_op = Sequel.pg_jsonb(:jsonb)
268
281
  class JSONBOp < JSONBaseOp
282
+ CONCAT = ["(".freeze, " || ".freeze, ")".freeze].freeze
269
283
  CONTAIN_ALL = ["(".freeze, " ?& ".freeze, ")".freeze].freeze
270
284
  CONTAIN_ANY = ["(".freeze, " ?| ".freeze, ")".freeze].freeze
271
285
  CONTAINS = ["(".freeze, " @> ".freeze, ")".freeze].freeze
272
286
  CONTAINED_BY = ["(".freeze, " <@ ".freeze, ")".freeze].freeze
287
+ DELETE_PATH = ["(".freeze, " #- ".freeze, ")".freeze].freeze
273
288
  HAS_KEY = ["(".freeze, " ? ".freeze, ")".freeze].freeze
274
289
 
290
+ # jsonb expression for deletion of the given argument from the
291
+ # current jsonb.
292
+ #
293
+ # jsonb_op - "a" # (jsonb - 'a')
294
+ def -(other)
295
+ self.class.new(super)
296
+ end
297
+
298
+ # jsonb expression for concatenation of the given jsonb into
299
+ # the current jsonb.
300
+ #
301
+ # jsonb_op.concat(:h) # (jsonb || h)
302
+ def concat(other)
303
+ json_op(CONCAT, wrap_input_jsonb(other))
304
+ end
305
+
275
306
  # Check if the receiver contains all of the keys in the given array:
276
307
  #
277
308
  # jsonb_op.contain_all(:a) # (jsonb ?& a)
@@ -300,6 +331,13 @@ module Sequel
300
331
  bool_op(CONTAINED_BY, wrap_input_jsonb(other))
301
332
  end
302
333
 
334
+ # Check if the other jsonb contains all entries in the receiver:
335
+ #
336
+ # jsonb_op.delete_path(:h) # (jsonb #- h)
337
+ def delete_path(other)
338
+ json_op(DELETE_PATH, wrap_input_array(other))
339
+ end
340
+
303
341
  # Check if the receiver contains the given key:
304
342
  #
305
343
  # jsonb_op.has_key?('a') # (jsonb ? 'a')
@@ -313,6 +351,21 @@ module Sequel
313
351
  self
314
352
  end
315
353
 
354
+ # Returns a json value for the object at the given path.
355
+ #
356
+ # jsonb_op.pretty # jsonb_pretty(jsonb)
357
+ def pretty
358
+ Sequel::SQL::StringExpression.new(:NOOP, function(:pretty))
359
+ end
360
+
361
+ # Returns a json value for the object at the given path.
362
+ #
363
+ # jsonb_op.set(['a', 'b'], h) # jsonb_set(jsonb, ARRAY['a', 'b'], h, true)
364
+ # jsonb_op.set(['a', 'b'], h, false) # jsonb_set(jsonb, ARRAY['a', 'b'], h, false)
365
+ def set(path, other, create_missing=true)
366
+ self.class.new(function(:set, wrap_input_array(path), wrap_input_jsonb(other), create_missing))
367
+ end
368
+
316
369
  private
317
370
 
318
371
  # Return a placeholder literal with the given str and args, wrapped