sequel 5.83.0 → 5.84.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sequel/adapters/shared/sqlite.rb +3 -1
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/misc.rb +8 -3
- data/lib/sequel/database/schema_methods.rb +2 -0
- data/lib/sequel/extensions/pg_json_ops.rb +328 -1
- data/lib/sequel/sql.rb +8 -5
- data/lib/sequel/version.rb +1 -1
- metadata +2 -236
- data/CHANGELOG +0 -1393
- data/README.rdoc +0 -936
- data/doc/advanced_associations.rdoc +0 -884
- data/doc/association_basics.rdoc +0 -1859
- data/doc/bin_sequel.rdoc +0 -146
- data/doc/cheat_sheet.rdoc +0 -255
- data/doc/code_order.rdoc +0 -104
- data/doc/core_extensions.rdoc +0 -405
- data/doc/dataset_basics.rdoc +0 -96
- data/doc/dataset_filtering.rdoc +0 -222
- data/doc/extensions.rdoc +0 -77
- data/doc/fork_safety.rdoc +0 -84
- data/doc/mass_assignment.rdoc +0 -98
- data/doc/migration.rdoc +0 -660
- data/doc/model_dataset_method_design.rdoc +0 -129
- data/doc/model_hooks.rdoc +0 -254
- data/doc/model_plugins.rdoc +0 -270
- data/doc/mssql_stored_procedures.rdoc +0 -43
- data/doc/object_model.rdoc +0 -563
- data/doc/opening_databases.rdoc +0 -439
- data/doc/postgresql.rdoc +0 -611
- data/doc/prepared_statements.rdoc +0 -144
- data/doc/querying.rdoc +0 -1070
- data/doc/reflection.rdoc +0 -120
- data/doc/release_notes/5.0.0.txt +0 -159
- data/doc/release_notes/5.1.0.txt +0 -31
- data/doc/release_notes/5.10.0.txt +0 -84
- data/doc/release_notes/5.11.0.txt +0 -83
- data/doc/release_notes/5.12.0.txt +0 -141
- data/doc/release_notes/5.13.0.txt +0 -27
- data/doc/release_notes/5.14.0.txt +0 -63
- data/doc/release_notes/5.15.0.txt +0 -39
- data/doc/release_notes/5.16.0.txt +0 -110
- data/doc/release_notes/5.17.0.txt +0 -31
- data/doc/release_notes/5.18.0.txt +0 -69
- data/doc/release_notes/5.19.0.txt +0 -28
- data/doc/release_notes/5.2.0.txt +0 -33
- data/doc/release_notes/5.20.0.txt +0 -89
- data/doc/release_notes/5.21.0.txt +0 -87
- data/doc/release_notes/5.22.0.txt +0 -48
- data/doc/release_notes/5.23.0.txt +0 -56
- data/doc/release_notes/5.24.0.txt +0 -56
- data/doc/release_notes/5.25.0.txt +0 -32
- data/doc/release_notes/5.26.0.txt +0 -35
- data/doc/release_notes/5.27.0.txt +0 -21
- data/doc/release_notes/5.28.0.txt +0 -16
- data/doc/release_notes/5.29.0.txt +0 -22
- data/doc/release_notes/5.3.0.txt +0 -121
- data/doc/release_notes/5.30.0.txt +0 -20
- data/doc/release_notes/5.31.0.txt +0 -148
- data/doc/release_notes/5.32.0.txt +0 -46
- data/doc/release_notes/5.33.0.txt +0 -24
- data/doc/release_notes/5.34.0.txt +0 -40
- data/doc/release_notes/5.35.0.txt +0 -56
- data/doc/release_notes/5.36.0.txt +0 -60
- data/doc/release_notes/5.37.0.txt +0 -30
- data/doc/release_notes/5.38.0.txt +0 -28
- data/doc/release_notes/5.39.0.txt +0 -19
- data/doc/release_notes/5.4.0.txt +0 -80
- data/doc/release_notes/5.40.0.txt +0 -40
- data/doc/release_notes/5.41.0.txt +0 -25
- data/doc/release_notes/5.42.0.txt +0 -136
- data/doc/release_notes/5.43.0.txt +0 -98
- data/doc/release_notes/5.44.0.txt +0 -32
- data/doc/release_notes/5.45.0.txt +0 -34
- data/doc/release_notes/5.46.0.txt +0 -87
- data/doc/release_notes/5.47.0.txt +0 -59
- data/doc/release_notes/5.48.0.txt +0 -14
- data/doc/release_notes/5.49.0.txt +0 -59
- data/doc/release_notes/5.5.0.txt +0 -61
- data/doc/release_notes/5.50.0.txt +0 -78
- data/doc/release_notes/5.51.0.txt +0 -47
- data/doc/release_notes/5.52.0.txt +0 -87
- data/doc/release_notes/5.53.0.txt +0 -23
- data/doc/release_notes/5.54.0.txt +0 -27
- data/doc/release_notes/5.55.0.txt +0 -21
- data/doc/release_notes/5.56.0.txt +0 -51
- data/doc/release_notes/5.57.0.txt +0 -23
- data/doc/release_notes/5.58.0.txt +0 -31
- data/doc/release_notes/5.59.0.txt +0 -73
- data/doc/release_notes/5.6.0.txt +0 -31
- data/doc/release_notes/5.60.0.txt +0 -22
- data/doc/release_notes/5.61.0.txt +0 -43
- data/doc/release_notes/5.62.0.txt +0 -132
- data/doc/release_notes/5.63.0.txt +0 -33
- data/doc/release_notes/5.64.0.txt +0 -50
- data/doc/release_notes/5.65.0.txt +0 -21
- data/doc/release_notes/5.66.0.txt +0 -24
- data/doc/release_notes/5.67.0.txt +0 -32
- data/doc/release_notes/5.68.0.txt +0 -61
- data/doc/release_notes/5.69.0.txt +0 -26
- data/doc/release_notes/5.7.0.txt +0 -108
- data/doc/release_notes/5.70.0.txt +0 -35
- data/doc/release_notes/5.71.0.txt +0 -21
- data/doc/release_notes/5.72.0.txt +0 -33
- data/doc/release_notes/5.73.0.txt +0 -66
- data/doc/release_notes/5.74.0.txt +0 -45
- data/doc/release_notes/5.75.0.txt +0 -35
- data/doc/release_notes/5.76.0.txt +0 -86
- data/doc/release_notes/5.77.0.txt +0 -63
- data/doc/release_notes/5.78.0.txt +0 -67
- data/doc/release_notes/5.79.0.txt +0 -28
- data/doc/release_notes/5.8.0.txt +0 -170
- data/doc/release_notes/5.80.0.txt +0 -40
- data/doc/release_notes/5.81.0.txt +0 -31
- data/doc/release_notes/5.82.0.txt +0 -61
- data/doc/release_notes/5.83.0.txt +0 -56
- data/doc/release_notes/5.9.0.txt +0 -99
- data/doc/schema_modification.rdoc +0 -679
- data/doc/security.rdoc +0 -443
- data/doc/sharding.rdoc +0 -286
- data/doc/sql.rdoc +0 -648
- data/doc/testing.rdoc +0 -204
- data/doc/thread_safety.rdoc +0 -15
- data/doc/transactions.rdoc +0 -250
- data/doc/validations.rdoc +0 -558
- data/doc/virtual_rows.rdoc +0 -265
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5677b07054121f55f100f0629d8102cabdd9db454263c5199a8f401bea891992
|
4
|
+
data.tar.gz: ca57e632e3e66c3a4003f988e5240da6a6eed0de9a143ac3985bd0603e0d9073
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ea8e58679c4ae2455588b584b959b3be691c177823cf336b77fa7b5910e716d9ca88e54024bbef44ec58d3fa8d66070acbf94e8c32a4294126ab2e618f4285e
|
7
|
+
data.tar.gz: acf4e565dd754b16ea0c07a11fe67cd21c9d5833ac1cf70c384a8da2c1b7c9ffd324358dbab9a8196d5a249365cc11870e6c807d07dbc631d359b413977f14ed
|
@@ -349,7 +349,7 @@ module Sequel
|
|
349
349
|
ps
|
350
350
|
end
|
351
351
|
|
352
|
-
# Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options
|
352
|
+
# Support creating STRICT AND/OR WITHOUT ROWID tables via :strict and :without_rowid options, and VIRTUAL tables with :using option.
|
353
353
|
def create_table_sql(name, generator, options)
|
354
354
|
if options[:strict] && options[:without_rowid]
|
355
355
|
"#{super} STRICT, WITHOUT ROWID"
|
@@ -357,6 +357,8 @@ module Sequel
|
|
357
357
|
"#{super} STRICT"
|
358
358
|
elsif options[:without_rowid]
|
359
359
|
"#{super} WITHOUT ROWID"
|
360
|
+
elsif options[:using]
|
361
|
+
"CREATE VIRTUAL TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)} USING #{options[:using]}"
|
360
362
|
else
|
361
363
|
super
|
362
364
|
end
|
@@ -34,7 +34,7 @@ module Sequel
|
|
34
34
|
uri = URI.parse(conn_string)
|
35
35
|
scheme = uri.scheme
|
36
36
|
c = adapter_class(scheme)
|
37
|
-
opts = c.send(:
|
37
|
+
opts = c.send(:options_from_uri, uri).merge!(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
|
38
38
|
end
|
39
39
|
when Hash
|
40
40
|
opts = conn_string.merge(opts)
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -72,18 +72,23 @@ module Sequel
|
|
72
72
|
# Converts a uri to an options hash. These options are then passed
|
73
73
|
# to a newly created database object.
|
74
74
|
def self.uri_to_options(uri)
|
75
|
-
|
75
|
+
{
|
76
76
|
:user => uri.user,
|
77
77
|
:password => uri.password,
|
78
78
|
:port => uri.port,
|
79
79
|
:host => uri.hostname,
|
80
80
|
:database => (m = /\/(.*)/.match(uri.path)) && (m[1])
|
81
81
|
}
|
82
|
+
end
|
83
|
+
private_class_method :uri_to_options
|
84
|
+
|
85
|
+
def self.options_from_uri(uri)
|
86
|
+
uri_options = uri_to_options(uri)
|
82
87
|
uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
|
83
88
|
uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
|
84
89
|
uri_options
|
85
90
|
end
|
86
|
-
private_class_method :
|
91
|
+
private_class_method :options_from_uri
|
87
92
|
|
88
93
|
# The options hash for this database
|
89
94
|
attr_reader :opts
|
@@ -266,7 +271,7 @@ module Sequel
|
|
266
271
|
keys = [:host, :database, :user]
|
267
272
|
opts = self.opts
|
268
273
|
if !keys.any?{|k| opts[k]} && opts[:uri]
|
269
|
-
opts = self.class.send(:
|
274
|
+
opts = self.class.send(:options_from_uri, URI.parse(opts[:uri]))
|
270
275
|
end
|
271
276
|
|
272
277
|
keys.each do |key|
|
@@ -191,6 +191,8 @@ module Sequel
|
|
191
191
|
# The +any+ type is treated like a SQLite column in a non-strict table,
|
192
192
|
# allowing any type of data to be stored. This option is supported on
|
193
193
|
# SQLite 3.37.0+.
|
194
|
+
# :using :: Create a VIRTUAL table with the given USING clause. The value should be
|
195
|
+
# a string, as it is used directly in the SQL query.
|
194
196
|
# :without_rowid :: Create a WITHOUT ROWID table. Every row in SQLite has a special
|
195
197
|
# 'rowid' column, that uniquely identifies that row within the table.
|
196
198
|
# If this option is used, the 'rowid' column is omitted, which can
|
@@ -132,6 +132,17 @@
|
|
132
132
|
# j.is_not_json(type: :array) # j IS NOT JSON ARRAY
|
133
133
|
# j.is_not_json(unique: true) # j IS NOT JSON WITH UNIQUE
|
134
134
|
#
|
135
|
+
# On PostgreSQL 17+, the additional JSON functions are supported (see method documentation
|
136
|
+
# for additional options):
|
137
|
+
#
|
138
|
+
# j.exists('$.foo') # json_exists(jsonb_column, '$.foo')
|
139
|
+
# j.value('$.foo') # json_value(jsonb_column, '$.foo')
|
140
|
+
# j.query('$.foo') # json_query(jsonb_column, '$.foo')
|
141
|
+
#
|
142
|
+
# j.exists('$.foo', passing: {a: 1}) # json_exists(jsonb_column, '$.foo' PASSING 1 AS a)
|
143
|
+
# j.value('$.foo', returning: Time) # json_value(jsonb_column, '$.foo' RETURNING timestamp)
|
144
|
+
# j.query('$.foo', wrapper: true) # json_query(jsonb_column, '$.foo' WITH WRAPPER)
|
145
|
+
#
|
135
146
|
# If you are also using the pg_json extension, you should load it before
|
136
147
|
# loading this extension. Doing so will allow you to use the #op method on
|
137
148
|
# JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
|
@@ -224,7 +235,25 @@ module Sequel
|
|
224
235
|
function(:each_text)
|
225
236
|
end
|
226
237
|
|
227
|
-
#
|
238
|
+
# Return whether the given JSON path yields any items in the receiver.
|
239
|
+
# Options:
|
240
|
+
#
|
241
|
+
# :on_error :: How to handle errors when evaluating the JSON path expression.
|
242
|
+
# true :: Return true
|
243
|
+
# false :: Return false (default behavior)
|
244
|
+
# :null :: Return nil
|
245
|
+
# :error :: raise a DatabaseError
|
246
|
+
# :passing :: Variables to pass to the JSON path expression. Keys are variable
|
247
|
+
# names, values are the values of the variable.
|
248
|
+
#
|
249
|
+
# json_op.exists("$.a") # json_exists(json, '$.a')
|
250
|
+
# json_op.exists("$.a", passing: {a: 1}) # json_exists(json, '$.a' PASSING 1 AS a)
|
251
|
+
# json_op.exists("$.a", on_error: :error) # json_exists(json, '$.a' ERROR ON ERROR)
|
252
|
+
def exists(path, opts=OPTS)
|
253
|
+
Sequel::SQL::BooleanExpression.new(:NOOP, JSONExistsOp.new(self, path, opts))
|
254
|
+
end
|
255
|
+
|
256
|
+
# Returns a JSON value for the object at the given path.
|
228
257
|
#
|
229
258
|
# json_op.extract('a') # json_extract_path(json, 'a')
|
230
259
|
# json_op.extract('a', 'b') # json_extract_path(json, 'a', 'b')
|
@@ -299,6 +328,35 @@ module Sequel
|
|
299
328
|
SQL::Function.new(function_name(:populate_recordset), arg, self)
|
300
329
|
end
|
301
330
|
|
331
|
+
# Return the result of applying the JSON path expression to the receiver, by default
|
332
|
+
# returning results as jsonb. Options:
|
333
|
+
#
|
334
|
+
# :on_empty :: How to handle case where path expression yields an empty set.
|
335
|
+
# Uses same values as :on_error option.
|
336
|
+
# :on_error :: How to handle errors when evaluating the JSON path expression:
|
337
|
+
# :null :: Return nil (default)
|
338
|
+
# :empty_array :: Return an empty array
|
339
|
+
# :empty_object :: Return an empty object
|
340
|
+
# :error :: raise a DatabaseError
|
341
|
+
# any other value :: used as default value
|
342
|
+
# :passing :: Variables to pass to the JSON path expression. Keys are variable
|
343
|
+
# names, values are the values of the variable.
|
344
|
+
# :returning :: The data type to return (jsonb by default)
|
345
|
+
# :wrapper :: How to wrap returned values:
|
346
|
+
# true, :unconditional :: Always wrap returning values in an array
|
347
|
+
# :conditional :: Only wrap multiple return values in an array
|
348
|
+
# :omit_quotes :: Do not wrap scalar strings in quotes
|
349
|
+
#
|
350
|
+
# json_op.query("$.a") # json_query(json, '$.a')
|
351
|
+
# json_op.query("$.a", passing: {a: 1}) # json_query(json, '$.a' PASSING 1 AS a)
|
352
|
+
# json_op.query("$.a", on_error: :empty_array) # json_query(json, '$.a' EMPTY ARRAY ON ERROR)
|
353
|
+
# json_op.query("$.a", returning: Time) # json_query(json, '$.a' RETURNING timestamp)
|
354
|
+
# json_op.query("$.a", on_empty: 2) # json_query(json, '$.a' DEFAULT 2 ON EMPTY)
|
355
|
+
# json_op.query("$.a", wrapper: true) # json_query(json, '$.a' WITH WRAPPER)
|
356
|
+
def query(path, opts=OPTS)
|
357
|
+
self.class.new(JSONQueryOp.new(self, path, opts))
|
358
|
+
end
|
359
|
+
|
302
360
|
# Returns a json value stripped of all internal null values.
|
303
361
|
#
|
304
362
|
# json_op.strip_nulls # json_strip_nulls(json)
|
@@ -329,6 +387,34 @@ module Sequel
|
|
329
387
|
function(:typeof)
|
330
388
|
end
|
331
389
|
|
390
|
+
# If called without arguments, operates as SQL::Wrapper#value. Otherwise,
|
391
|
+
# return the result of applying the JSON path expression to the receiver, by default
|
392
|
+
# returning results as text. Options:
|
393
|
+
#
|
394
|
+
# :on_empty :: How to handle case where path expression yields an empty set.
|
395
|
+
# Uses same values as :on_error option.
|
396
|
+
# :on_error :: How to handle errors when evaluating the JSON path expression.
|
397
|
+
# :null :: Return nil (default)
|
398
|
+
# :error :: raise a DatabaseError
|
399
|
+
# any other value :: used as default value
|
400
|
+
# :passing :: Variables to pass to the JSON path expression. Keys are variable
|
401
|
+
# names, values are the values of the variable.
|
402
|
+
# :returning :: The data type to return (text by default)
|
403
|
+
#
|
404
|
+
# json_op.value("$.a") # json_value(json, '$.a')
|
405
|
+
# json_op.value("$.a", passing: {a: 1}) # json_value(json, '$.a' PASSING 1 AS a)
|
406
|
+
# json_op.value("$.a", on_error: :error) # json_value(json, '$.a' ERROR ON ERROR)
|
407
|
+
# json_op.value("$.a", returning: Time) # json_value(json, '$.a' RETURNING timestamp)
|
408
|
+
# json_op.value("$.a", on_empty: 2) # json_value(json, '$.a' DEFAULT 2 ON EMPTY)
|
409
|
+
def value(path=(no_args_given = true), opts=OPTS)
|
410
|
+
if no_args_given
|
411
|
+
# Act as SQL::Wrapper#value
|
412
|
+
super()
|
413
|
+
else
|
414
|
+
Sequel::SQL::StringExpression.new(:NOOP, JSONValueOp.new(self, path, opts))
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
332
418
|
private
|
333
419
|
|
334
420
|
# Internals of IS [NOT] JSON support
|
@@ -705,6 +791,247 @@ module Sequel
|
|
705
791
|
end
|
706
792
|
end
|
707
793
|
|
794
|
+
# Object representing json_exists calls
|
795
|
+
class JSONExistsOp < SQL::Expression
|
796
|
+
ON_ERROR_SQL = {
|
797
|
+
true => 'TRUE',
|
798
|
+
false => 'FALSE',
|
799
|
+
:null => 'UNKNOWN',
|
800
|
+
:error => 'ERROR',
|
801
|
+
}.freeze
|
802
|
+
private_constant :ON_ERROR_SQL
|
803
|
+
|
804
|
+
# Expression (context_item in PostgreSQL terms), usually JSONBaseOp instance
|
805
|
+
attr_reader :expr
|
806
|
+
|
807
|
+
# JSON path expression to apply against the expression
|
808
|
+
attr_reader :path
|
809
|
+
|
810
|
+
# Variables to set in the JSON path expression
|
811
|
+
attr_reader :passing
|
812
|
+
|
813
|
+
# How to handle errors when evaluating the JSON path expression
|
814
|
+
attr_reader :on_error
|
815
|
+
|
816
|
+
# See JSONBaseOp#exists for documentation on the options.
|
817
|
+
def initialize(expr, path, opts=OPTS)
|
818
|
+
@expr = expr
|
819
|
+
@path = path
|
820
|
+
@passing = opts[:passing]
|
821
|
+
@on_error = opts[:on_error]
|
822
|
+
freeze
|
823
|
+
end
|
824
|
+
|
825
|
+
# Append the SQL function call expression to the SQL
|
826
|
+
def to_s_append(ds, sql)
|
827
|
+
to_s_append_function_name(ds, sql)
|
828
|
+
to_s_append_args_passing(ds, sql)
|
829
|
+
to_s_append_on_error(ds, sql)
|
830
|
+
sql << ')'
|
831
|
+
end
|
832
|
+
|
833
|
+
# Support transforming of function call expression
|
834
|
+
def sequel_ast_transform(transformer)
|
835
|
+
opts = {}
|
836
|
+
transform_opts(transformer, opts)
|
837
|
+
self.class.new(transformer.call(@expr), @path, opts)
|
838
|
+
end
|
839
|
+
|
840
|
+
private
|
841
|
+
|
842
|
+
# Set the :passing and :on_error options when doing an
|
843
|
+
# AST transform.
|
844
|
+
def transform_opts(transformer, opts)
|
845
|
+
if @passing
|
846
|
+
passing = opts[:passing] = {}
|
847
|
+
@passing.each do |k, v|
|
848
|
+
passing[k] = transformer.call(v)
|
849
|
+
end
|
850
|
+
end
|
851
|
+
|
852
|
+
opts[:on_error] = @on_error
|
853
|
+
end
|
854
|
+
|
855
|
+
def to_s_append_function_name(ds, sql)
|
856
|
+
sql << 'json_exists('
|
857
|
+
end
|
858
|
+
|
859
|
+
# Append the expression, path, and optional PASSING fragments
|
860
|
+
def to_s_append_args_passing(ds, sql)
|
861
|
+
ds.literal_append(sql, @expr)
|
862
|
+
sql << ', '
|
863
|
+
ds.literal_append(sql, @path)
|
864
|
+
|
865
|
+
if (passing = @passing) && !passing.empty?
|
866
|
+
sql << ' PASSING '
|
867
|
+
comma = false
|
868
|
+
passing.each do |k, v|
|
869
|
+
if comma
|
870
|
+
sql << ', '
|
871
|
+
else
|
872
|
+
comma = true
|
873
|
+
end
|
874
|
+
ds.literal_append(sql, v)
|
875
|
+
sql << " AS " << k.to_s
|
876
|
+
end
|
877
|
+
end
|
878
|
+
end
|
879
|
+
|
880
|
+
# Append the optional ON ERROR fragments
|
881
|
+
def to_s_append_on_error(ds, sql)
|
882
|
+
unless @on_error.nil?
|
883
|
+
sql << " "
|
884
|
+
to_s_append_on_value(ds, sql, @on_error)
|
885
|
+
sql << " ON ERROR"
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
889
|
+
# Append the value to use for ON ERROR
|
890
|
+
def to_s_append_on_value(ds, sql, value)
|
891
|
+
sql << ON_ERROR_SQL.fetch(value)
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
# Object representing json_value calls
|
896
|
+
class JSONValueOp < JSONExistsOp
|
897
|
+
ON_SQL = {
|
898
|
+
:null => 'NULL',
|
899
|
+
:error => 'ERROR',
|
900
|
+
}.freeze
|
901
|
+
private_constant :ON_SQL
|
902
|
+
|
903
|
+
# The database type to cast returned values to
|
904
|
+
attr_reader :returning
|
905
|
+
|
906
|
+
# How to handle cases where the JSON path expression evaluation yields
|
907
|
+
# an empty set.
|
908
|
+
attr_reader :on_empty
|
909
|
+
|
910
|
+
# See JSONBaseOp#value for documentation of the options.
|
911
|
+
def initialize(expr, path, opts=OPTS)
|
912
|
+
@returning = opts[:returning]
|
913
|
+
@on_empty = opts[:on_empty]
|
914
|
+
super
|
915
|
+
end
|
916
|
+
|
917
|
+
private
|
918
|
+
|
919
|
+
# Also handle transforming the returning and on_empty options.
|
920
|
+
def transform_opts(transformer, opts)
|
921
|
+
super
|
922
|
+
opts[:returning] = @returning
|
923
|
+
on_error = @on_error
|
924
|
+
on_error = transformer.call(on_error) unless on_sql_value(on_error)
|
925
|
+
opts[:on_error] = on_error
|
926
|
+
on_empty = @on_empty
|
927
|
+
on_empty = transformer.call(on_empty) unless on_sql_value(on_empty)
|
928
|
+
opts[:on_empty] = on_empty
|
929
|
+
end
|
930
|
+
|
931
|
+
def to_s_append_function_name(ds, sql)
|
932
|
+
sql << 'json_value('
|
933
|
+
end
|
934
|
+
|
935
|
+
# Also append the optional RETURNING fragment
|
936
|
+
def to_s_append_args_passing(ds, sql)
|
937
|
+
super
|
938
|
+
|
939
|
+
if @returning
|
940
|
+
sql << ' RETURNING ' << ds.db.cast_type_literal(@returning).to_s
|
941
|
+
end
|
942
|
+
end
|
943
|
+
|
944
|
+
# Also append the optional ON EMPTY fragment
|
945
|
+
def to_s_append_on_error(ds, sql)
|
946
|
+
unless @on_empty.nil?
|
947
|
+
sql << " "
|
948
|
+
to_s_append_on_value(ds, sql, @on_empty)
|
949
|
+
sql << " ON EMPTY"
|
950
|
+
end
|
951
|
+
|
952
|
+
super
|
953
|
+
end
|
954
|
+
|
955
|
+
# Handle DEFAULT values in ON EMPTY/ON ERROR fragments
|
956
|
+
def to_s_append_on_value(ds, sql, value)
|
957
|
+
if v = on_sql_value(value)
|
958
|
+
sql << v
|
959
|
+
else
|
960
|
+
sql << 'DEFAULT '
|
961
|
+
default_literal_append(ds, sql, value)
|
962
|
+
end
|
963
|
+
end
|
964
|
+
|
965
|
+
# Do not auto paramterize default value, as PostgreSQL doesn't allow it.
|
966
|
+
def default_literal_append(ds, sql, v)
|
967
|
+
if sql.respond_to?(:skip_auto_param)
|
968
|
+
sql.skip_auto_param do
|
969
|
+
ds.literal_append(sql, v)
|
970
|
+
end
|
971
|
+
else
|
972
|
+
ds.literal_append(sql, v)
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
def on_sql_value(value)
|
977
|
+
ON_SQL[value]
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
981
|
+
# Object representing json_query calls
|
982
|
+
class JSONQueryOp < JSONValueOp
|
983
|
+
ON_SQL = {
|
984
|
+
:null => 'NULL',
|
985
|
+
:error => 'ERROR',
|
986
|
+
:empty_array => 'EMPTY ARRAY',
|
987
|
+
:empty_object => 'EMPTY OBJECT',
|
988
|
+
}.freeze
|
989
|
+
private_constant :ON_SQL
|
990
|
+
|
991
|
+
WRAPPER = {
|
992
|
+
:conditional => ' WITH CONDITIONAL WRAPPER',
|
993
|
+
:unconditional => ' WITH WRAPPER',
|
994
|
+
:omit_quotes => ' OMIT QUOTES'
|
995
|
+
}
|
996
|
+
WRAPPER[true] = WRAPPER[:unconditional]
|
997
|
+
WRAPPER.freeze
|
998
|
+
private_constant :WRAPPER
|
999
|
+
|
1000
|
+
# How to handle wrapping of results
|
1001
|
+
attr_reader :wrapper
|
1002
|
+
|
1003
|
+
# See JSONBaseOp#query for documentation of the options.
|
1004
|
+
def initialize(expr, path, opts=OPTS)
|
1005
|
+
@wrapper = opts[:wrapper]
|
1006
|
+
super
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
private
|
1010
|
+
|
1011
|
+
# Also handle transforming the wrapper option
|
1012
|
+
def transform_opts(transformer, opts)
|
1013
|
+
super
|
1014
|
+
opts[:wrapper] = @wrapper
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def to_s_append_function_name(ds, sql)
|
1018
|
+
sql << 'json_query('
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
# Also append the optional WRAPPER/OMIT QUOTES fragment
|
1022
|
+
def to_s_append_args_passing(ds, sql)
|
1023
|
+
super
|
1024
|
+
|
1025
|
+
if @wrapper
|
1026
|
+
sql << WRAPPER.fetch(@wrapper)
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
def on_sql_value(value)
|
1031
|
+
ON_SQL[value]
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
708
1035
|
module JSONOpMethods
|
709
1036
|
# Wrap the receiver in an JSONOp so you can easily use the PostgreSQL
|
710
1037
|
# json functions and operators with it.
|
data/lib/sequel/sql.rb
CHANGED
@@ -153,13 +153,16 @@ module Sequel
|
|
153
153
|
class ComplexExpression < Expression
|
154
154
|
# A hash of the opposite for each operator symbol, used for inverting
|
155
155
|
# objects.
|
156
|
-
|
156
|
+
OPERATOR_INVERSIONS = {:AND => :OR, :OR => :AND, :< => :>=, :> => :<=,
|
157
157
|
:<= => :>, :>= => :<, :'=' => :'!=' , :'!=' => :'=', :LIKE => :'NOT LIKE',
|
158
158
|
:'NOT LIKE' => :LIKE, :~ => :'!~', :'!~' => :~, :IN => :'NOT IN',
|
159
159
|
:'NOT IN' => :IN, :IS => :'IS NOT', :'IS NOT' => :IS, :'~*' => :'!~*',
|
160
160
|
:'!~*' => :'~*', :NOT => :NOOP, :NOOP => :NOT, :ILIKE => :'NOT ILIKE',
|
161
161
|
:'NOT ILIKE'=>:ILIKE}.freeze
|
162
162
|
|
163
|
+
# SEQUEL6: Remove
|
164
|
+
OPERTATOR_INVERSIONS = OPERATOR_INVERSIONS
|
165
|
+
|
163
166
|
# Standard mathematical operators used in +NumericMethods+
|
164
167
|
MATHEMATICAL_OPERATORS = [:+, :-, :/, :*, :**].freeze
|
165
168
|
|
@@ -1142,9 +1145,9 @@ module Sequel
|
|
1142
1145
|
when BooleanExpression
|
1143
1146
|
case op = ce.op
|
1144
1147
|
when :AND, :OR
|
1145
|
-
BooleanExpression.new(
|
1148
|
+
BooleanExpression.new(OPERATOR_INVERSIONS[op], *ce.args.map{|a| BooleanExpression.invert(a)})
|
1146
1149
|
when :IN, :"NOT IN"
|
1147
|
-
BooleanExpression.new(
|
1150
|
+
BooleanExpression.new(OPERATOR_INVERSIONS[op], *ce.args.dup)
|
1148
1151
|
else
|
1149
1152
|
if ce.args.length == 2
|
1150
1153
|
case ce.args[1]
|
@@ -1153,10 +1156,10 @@ module Sequel
|
|
1153
1156
|
# can result in incorrect behavior for ANY/SOME/ALL operators.
|
1154
1157
|
BooleanExpression.new(:NOT, ce)
|
1155
1158
|
else
|
1156
|
-
BooleanExpression.new(
|
1159
|
+
BooleanExpression.new(OPERATOR_INVERSIONS[op], *ce.args.dup)
|
1157
1160
|
end
|
1158
1161
|
else
|
1159
|
-
BooleanExpression.new(
|
1162
|
+
BooleanExpression.new(OPERATOR_INVERSIONS[op], *ce.args.dup)
|
1160
1163
|
end
|
1161
1164
|
end
|
1162
1165
|
when StringExpression, NumericExpression
|
data/lib/sequel/version.rb
CHANGED
@@ -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 =
|
9
|
+
MINOR = 84
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|