sequel 4.26.0 → 4.27.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/CHANGELOG +30 -0
- data/bin/sequel +8 -0
- data/doc/opening_databases.rdoc +3 -1
- data/doc/postgresql.rdoc +13 -0
- data/doc/release_notes/4.27.0.txt +78 -0
- data/doc/thread_safety.rdoc +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +4 -0
- data/lib/sequel/adapters/shared/postgres.rb +1 -1
- data/lib/sequel/core.rb +8 -18
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +17 -4
- data/lib/sequel/dataset/actions.rb +38 -9
- data/lib/sequel/extensions/pg_json_ops.rb +58 -5
- data/lib/sequel/extensions/schema_dumper.rb +12 -1
- data/lib/sequel/model/base.rb +30 -14
- data/lib/sequel/plugins/active_model.rb +7 -0
- data/lib/sequel/plugins/before_after_save.rb +48 -0
- data/lib/sequel/plugins/defaults_setter.rb +8 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +10 -0
- data/spec/bin_spec.rb +4 -0
- data/spec/core/dataset_spec.rb +34 -0
- data/spec/core/schema_generator_spec.rb +13 -0
- data/spec/core/schema_spec.rb +17 -0
- data/spec/extensions/active_model_spec.rb +70 -108
- data/spec/extensions/before_after_save_spec.rb +40 -0
- data/spec/extensions/pg_json_ops_spec.rb +46 -0
- data/spec/extensions/schema_dumper_spec.rb +18 -0
- data/spec/integration/dataset_test.rb +14 -0
- data/spec/integration/schema_test.rb +6 -0
- data/spec/model/class_dataset_methods_spec.rb +4 -0
- data/spec/model/model_spec.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8e0006e87c72a9cee83298b0fab32a7ccea74ef
|
4
|
+
data.tar.gz: 46a222bb7aa35ce30d2a931c56c0cc49d8fd1b3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/doc/opening_databases.rdoc
CHANGED
@@ -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.
|
data/doc/thread_safety.rdoc
CHANGED
@@ -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
|
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 =~ /\
|
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(:
|
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
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
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:
|
@@ -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
|
-
|
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
|
257
|
+
opts = opts.merge(:type => type)
|
251
258
|
end
|
252
|
-
|
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
|
-
#
|
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).
|
645
|
-
|
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.
|
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.
|
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
|
62
|
-
# j.
|
63
|
-
# j.
|
64
|
-
# j.
|
65
|
-
# j.
|
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
|