# frozen-string-literal: true
#
# The pg_json_ops extension adds support to Sequel's DSL to make
# it easier to call PostgreSQL JSON functions and operators (added
# first in PostgreSQL 9.3). It also supports the JSONB functions
# and operators added in PostgreSQL 9.4.
#
# To load the extension:
#
# Sequel.extension :pg_json_ops
#
# The most common usage is passing an expression to Sequel.pg_json_op
# or Sequel.pg_jsonb_op:
#
# j = Sequel.pg_json_op(:json_column)
# jb = Sequel.pg_jsonb_op(:jsonb_column)
#
# If you have also loaded the pg_json extension, you can use
# Sequel.pg_json or Sequel.pg_jsonb as well:
#
# j = Sequel.pg_json(:json_column)
# jb = Sequel.pg_jsonb(:jsonb_column)
#
# Also, on most Sequel expression objects, you can call the pg_json
# or pg_jsonb method:
#
# j = Sequel[:json_column].pg_json
# jb = Sequel[:jsonb_column].pg_jsonb
#
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
# or you have loaded the core_refinements extension
# and have activated refinements for the file, you can also use Symbol#pg_json or
# Symbol#pg_jsonb:
#
# j = :json_column.pg_json
# jb = :jsonb_column.pg_jsonb
#
# This creates a Sequel::Postgres::JSONOp or Sequel::Postgres::JSONBOp object that can be used
# for easier querying. The following methods are available for both JSONOp and JSONBOp instances:
#
# j[1] # (json_column -> 1)
# j[%w'a b'] # (json_column #> ARRAY['a','b'])
# j.get_text(1) # (json_column ->> 1)
# j.get_text(%w'a b') # (json_column #>> ARRAY['a','b'])
# j.extract('a', 'b') # json_extract_path(json_column, 'a', 'b')
# j.extract_text('a', 'b') # json_extract_path_text(json_column, 'a', 'b')
#
# j.array_length # json_array_length(json_column)
# j.array_elements # json_array_elements(json_column)
# j.array_elements_text # json_array_elements_text(json_column)
# j.each # json_each(json_column)
# j.each_text # json_each_text(json_column)
# j.keys # json_object_keys(json_column)
# j.typeof # json_typeof(json_column)
# j.strip_nulls # json_strip_nulls(json_column)
#
# j.populate(:a) # json_populate_record(:a, json_column)
# j.populate_set(:a) # json_populate_recordset(:a, json_column)
# j.to_record # json_to_record(json_column)
# j.to_recordset # json_to_recordset(json_column)
#
# There are additional methods are are only supported on JSONBOp instances:
#
# j - 1 # (jsonb_column - 1)
# j.concat(:h) # (jsonb_column || h)
# j.contain_all(:a) # (jsonb_column ?& a)
# j.contain_any(:a) # (jsonb_column ?| a)
# j.contains(:h) # (jsonb_column @> h)
# j.contained_by(:h) # (jsonb_column <@ h)
# j.delete_path(%w'0 a') # (jsonb_column #- ARRAY['0','a'])
# j.has_key?('a') # (jsonb_column ? 'a')
# j.insert(%w'0 a', 'a'=>1) # jsonb_insert(jsonb_column, ARRAY[0, 'a'], '{"a":1}'::jsonb, false)
# j.pretty # jsonb_pretty(jsonb_column)
# j.set(%w'0 a', :h) # jsonb_set(jsonb_column, ARRAY['0','a'], h, true)
#
# j.set_lax(%w'0 a', :h, false, 'raise_exception')
# # jsonb_set_lax(jsonb_column, ARRAY['0','a'], h, false, 'raise_exception')
#
# On PostgreSQL 12+ SQL/JSON path functions and operators are supported:
#
# j.path_exists('$.foo') # (jsonb_column @? '$.foo')
# j.path_match('$.foo') # (jsonb_column @@ '$.foo')
#
# j.path_exists!('$.foo') # jsonb_path_exists(jsonb_column, '$.foo')
# j.path_match!('$.foo') # jsonb_path_match(jsonb_column, '$.foo')
# j.path_query('$.foo') # jsonb_path_query(jsonb_column, '$.foo')
# j.path_query_array('$.foo') # jsonb_path_query_array(jsonb_column, '$.foo')
# j.path_query_first('$.foo') # jsonb_path_query_first(jsonb_column, '$.foo')
#
# On PostgreSQL 13+ timezone-aware SQL/JSON path functions and operators are supported:
#
# j.path_exists_tz!('$.foo') # jsonb_path_exists_tz(jsonb_column, '$.foo')
# j.path_match_tz!('$.foo') # jsonb_path_match_tz(jsonb_column, '$.foo')
# j.path_query_tz('$.foo') # jsonb_path_query_tz(jsonb_column, '$.foo')
# j.path_query_array_tz('$.foo') # jsonb_path_query_array_tz(jsonb_column, '$.foo')
# j.path_query_first_tz('$.foo') # jsonb_path_query_first_tz(jsonb_column, '$.foo')
#
# For the PostgreSQL 12+ SQL/JSON path functions, one argument is required (+path+) and
# two more arguments are optional (+vars+ and +silent+). +path+ specifies the JSON path.
# +vars+ specifies a hash or a string in JSON format of named variables to be
# substituted in +path+. +silent+ specifies whether errors are suppressed. By default,
# errors are not suppressed.
#
# On PostgreSQL 14+, The JSONB [] method will use subscripts instead of being
# the same as +get+, if the value being wrapped is an identifer:
#
# Sequel.pg_jsonb_op(:jsonb_column)[1] # jsonb_column[1]
# Sequel.pg_jsonb_op(:jsonb_column)[1][2] # jsonb_column[1][2]
# Sequel.pg_jsonb_op(Sequel[:j][:b])[1] # j.b[1]
#
# This support allows you to use JSONB subscripts in UPDATE statements to update only
# part of a column:
#
# c = Sequel.pg_jsonb_op(:c)
# DB[:t].update(c['key1'] => '1', c['key2'] => '"a"')
# # UPDATE "t" SET "c"['key1'] = '1', "c"['key2'] = '"a"'
#
# Note that you have to provide the value of a JSONB subscript as a JSONB value, so this
# will update +key1+ to use the number 1, and +key2+ to use the string a.
# For this reason it may be simpler to use +to_json+:
#
# c = Sequel.pg_jsonb_op(:c)
# DB[:t].update(c['key1'] => 1.to_json, c['key2'] => "a".to_json)
#
# If you are also using the pg_json extension, you should load it before
# loading this extension. Doing so will allow you to use the #op method on
# JSONHash, JSONHarray, JSONBHash, and JSONBArray, allowing you to perform json/jsonb operations
# on json/jsonb literals.
#
# In order to get the automatic conversion from a ruby array to a PostgreSQL array
# (as shown in the #[] and #get_text examples above), you need to load the pg_array
# extension.
#
# Related modules: Sequel::Postgres::JSONBaseOp, Sequel::Postgres::JSONOp,
# Sequel::Postgres::JSONBOp
#
module Sequel
module Postgres
# The JSONBaseOp class is a simple container for a single object that
# defines methods that yield Sequel expression objects representing
# PostgreSQL json operators and functions.
#
# In the method documentation examples, assume that:
#
# json_op = Sequel.pg_json(:json)
class JSONBaseOp < Sequel::SQL::Wrapper
GET = ["(".freeze, " -> ".freeze, ")".freeze].freeze
GET_TEXT = ["(".freeze, " ->> ".freeze, ")".freeze].freeze
GET_PATH = ["(".freeze, " #> ".freeze, ")".freeze].freeze
GET_PATH_TEXT = ["(".freeze, " #>> ".freeze, ")".freeze].freeze
# Get JSON array element or object field as json. If an array is given,
# gets the object at the specified path.
#
# json_op[1] # (json -> 1)
# json_op['a'] # (json -> 'a')
# json_op[%w'a b'] # (json #> ARRAY['a', 'b'])
def [](key)
if is_array?(key)
json_op(GET_PATH, wrap_array(key))
else
json_op(GET, key)
end
end
alias get []
# Returns a set of json values for the elements in the json array.
#
# json_op.array_elements # json_array_elements(json)
def array_elements
function(:array_elements)
end
# Returns a set of text values for the elements in the json array.
#
# json_op.array_elements_text # json_array_elements_text(json)
def array_elements_text
function(:array_elements_text)
end
# Get the length of the outermost json array.
#
# json_op.array_length # json_array_length(json)
def array_length
Sequel::SQL::NumericExpression.new(:NOOP, function(:array_length))
end
# Returns a set of key and value pairs, where the keys
# are text and the values are JSON.
#
# json_op.each # json_each(json)
def each
function(:each)
end
# Returns a set of key and value pairs, where the keys
# and values are both text.
#
# json_op.each_text # json_each_text(json)
def each_text
function(:each_text)
end
# Returns a json value for the object at the given path.
#
# json_op.extract('a') # json_extract_path(json, 'a')
# json_op.extract('a', 'b') # json_extract_path(json, 'a', 'b')
def extract(*a)
self.class.new(function(:extract_path, *a))
end
# Returns a text value for the object at the given path.
#
# json_op.extract_text('a') # json_extract_path_text(json, 'a')
# json_op.extract_text('a', 'b') # json_extract_path_text(json, 'a', 'b')
def extract_text(*a)
Sequel::SQL::StringExpression.new(:NOOP, function(:extract_path_text, *a))
end
# Get JSON array element or object field as text. If an array is given,
# gets the object at the specified path.
#
# json_op.get_text(1) # (json ->> 1)
# json_op.get_text('a') # (json ->> 'a')
# json_op.get_text(%w'a b') # (json #>> ARRAY['a', 'b'])
def get_text(key)
if is_array?(key)
json_op(GET_PATH_TEXT, wrap_array(key))
else
json_op(GET_TEXT, key)
end
end
# Returns a set of keys AS text in the json object.
#
# json_op.keys # json_object_keys(json)
def keys
function(:object_keys)
end
# Expands the given argument using the columns in the json.
#
# json_op.populate(arg) # json_populate_record(arg, json)
def populate(arg)
SQL::Function.new(function_name(:populate_record), arg, self)
end
# Expands the given argument using the columns in the json.
#
# json_op.populate_set(arg) # json_populate_recordset(arg, json)
def populate_set(arg)
SQL::Function.new(function_name(:populate_recordset), arg, self)
end
# Returns a json value stripped of all internal null values.
#
# json_op.strip_nulls # json_strip_nulls(json)
def strip_nulls
self.class.new(function(:strip_nulls))
end
# Builds arbitrary record from json object. You need to define the
# structure of the record using #as on the resulting object:
#
# json_op.to_record.as(:x, [Sequel.lit('a integer'), Sequel.lit('b text')]) # json_to_record(json) AS x(a integer, b text)
def to_record
function(:to_record)
end
# Builds arbitrary set of records from json array of objects. You need to define the
# structure of the records using #as on the resulting object:
#
# json_op.to_recordset.as(:x, [Sequel.lit('a integer'), Sequel.lit('b text')]) # json_to_recordset(json) AS x(a integer, b text)
def to_recordset
function(:to_recordset)
end
# Returns the type of the outermost json value as text.
#
# json_op.typeof # json_typeof(json)
def typeof
function(:typeof)
end
private
# Return a placeholder literal with the given str and args, wrapped
# in an JSONOp or JSONBOp, used by operators that return json or jsonb.
def json_op(str, args)
self.class.new(Sequel::SQL::PlaceholderLiteralString.new(str, [self, args]))
end
# Return a function with the given name, and the receiver as the first
# argument, with any additional arguments given.
def function(name, *args)
SQL::Function.new(function_name(name), self, *args)
end
# Whether the given object represents an array in PostgreSQL.
def is_array?(a)
a.is_a?(Array) || (defined?(PGArray) && a.is_a?(PGArray)) || (defined?(ArrayOp) && a.is_a?(ArrayOp))
end
# Automatically wrap argument in a PGArray if it is a plain Array.
# Requires that the pg_array extension has been loaded to work.
def wrap_array(arg)
if arg.instance_of?(Array) && Sequel.respond_to?(:pg_array)
Sequel.pg_array(arg)
else
arg
end
end
end
# JSONBaseOp subclass for the json type
class JSONOp < JSONBaseOp
# Return the receiver, since it is already a JSONOp.
def pg_json
self
end
private
# The json type functions are prefixed with json_
def function_name(name)
"json_#{name}"
end
end
# JSONBaseOp subclass for the jsonb type.
#
# In the method documentation examples, assume that:
#
# jsonb_op = Sequel.pg_jsonb(:jsonb)
class JSONBOp < JSONBaseOp
CONCAT = ["(".freeze, " || ".freeze, ")".freeze].freeze
CONTAIN_ALL = ["(".freeze, " ?& ".freeze, ")".freeze].freeze
CONTAIN_ANY = ["(".freeze, " ?| ".freeze, ")".freeze].freeze
CONTAINS = ["(".freeze, " @> ".freeze, ")".freeze].freeze
CONTAINED_BY = ["(".freeze, " <@ ".freeze, ")".freeze].freeze
DELETE_PATH = ["(".freeze, " #- ".freeze, ")".freeze].freeze
HAS_KEY = ["(".freeze, " ? ".freeze, ")".freeze].freeze
PATH_EXISTS = ["(".freeze, " @? ".freeze, ")".freeze].freeze
PATH_MATCH = ["(".freeze, " @@ ".freeze, ")".freeze].freeze
# Support subscript syntax for JSONB.
def [](key)
if is_array?(key)
super
else
case @value
when Symbol, SQL::Identifier, SQL::QualifiedIdentifier, JSONBSubscriptOp
# Only use subscripts for identifiers. In other cases, switching from
# the -> operator to [] for subscripts causes SQL syntax issues. You
# only need the [] for subscripting when doing assignment, and
# assignment is generally done on identifiers.
self.class.new(JSONBSubscriptOp.new(self, key))
else
super
end
end
end
# jsonb expression for deletion of the given argument from the
# current jsonb.
#
# jsonb_op - "a" # (jsonb - 'a')
def -(other)
self.class.new(super)
end
# jsonb expression for concatenation of the given jsonb into
# the current jsonb.
#
# jsonb_op.concat(:h) # (jsonb || h)
def concat(other)
json_op(CONCAT, wrap_input_jsonb(other))
end
# Check if the receiver contains all of the keys in the given array:
#
# jsonb_op.contain_all(:a) # (jsonb ?& a)
def contain_all(other)
bool_op(CONTAIN_ALL, wrap_input_array(other))
end
# Check if the receiver contains any of the keys in the given array:
#
# jsonb_op.contain_any(:a) # (jsonb ?| a)
def contain_any(other)
bool_op(CONTAIN_ANY, wrap_input_array(other))
end
# Check if the receiver contains all entries in the other jsonb:
#
# jsonb_op.contains(:h) # (jsonb @> h)
def contains(other)
bool_op(CONTAINS, wrap_input_jsonb(other))
end
# Check if the other jsonb contains all entries in the receiver:
#
# jsonb_op.contained_by(:h) # (jsonb <@ h)
def contained_by(other)
bool_op(CONTAINED_BY, wrap_input_jsonb(other))
end
# Removes the given path from the receiver.
#
# jsonb_op.delete_path(:h) # (jsonb #- h)
def delete_path(other)
json_op(DELETE_PATH, wrap_input_array(other))
end
# Check if the receiver contains the given key:
#
# jsonb_op.has_key?('a') # (jsonb ? 'a')
def has_key?(key)
bool_op(HAS_KEY, key)
end
alias include? has_key?
# Inserts the given jsonb value at the given path in the receiver.
# The default is to insert the value before the given path, but
# insert_after can be set to true to insert it after the given path.
#
# jsonb_op.insert(['a', 'b'], h) # jsonb_insert(jsonb, ARRAY['a', 'b'], h, false)
# jsonb_op.insert(['a', 'b'], h, true) # jsonb_insert(jsonb, ARRAY['a', 'b'], h, true)
def insert(path, other, insert_after=false)
self.class.new(function(:insert, wrap_input_array(path), wrap_input_jsonb(other), insert_after))
end
# Returns whether the JSON path returns any item for the json object.
#
# json_op.path_exists("$.foo") # (json @? '$.foo')
def path_exists(path)
bool_op(PATH_EXISTS, path)
end
# Returns whether the JSON path returns any item for the json object.
#
# json_op.path_exists!("$.foo")
# # jsonb_path_exists(json, '$.foo')
#
# json_op.path_exists!("$.foo ? ($ > $x)", x: 2)
# # jsonb_path_exists(json, '$.foo ? ($ > $x)', '{"x":2}')
#
# json_op.path_exists!("$.foo ? ($ > $x)", {x: 2}, true)
# # jsonb_path_exists(json, '$.foo ? ($ > $x)', '{"x":2}', true)
def path_exists!(path, vars=nil, silent=nil)
Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_exists, path, vars, silent))
end
# The same as #path_exists!, except that timezone-aware conversions are used for date/time values.
def path_exists_tz!(path, vars=nil, silent=nil)
Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_exists_tz, path, vars, silent))
end
# Returns the first item of the result of JSON path predicate check for the json object.
# Returns nil if the first item is not true or false.
#
# json_op.path_match("$.foo") # (json @@ '$.foo')
def path_match(path)
bool_op(PATH_MATCH, path)
end
# Returns the first item of the result of JSON path predicate check for the json object.
# Returns nil if the first item is not true or false and silent is true.
#
# json_op.path_match!("$.foo")
# # jsonb_path_match(json, '$.foo')
#
# json_op.path_match!("$.foo ? ($ > $x)", x: 2)
# # jsonb_path_match(json, '$.foo ? ($ > $x)', '{"x":2}')
#
# json_op.path_match!("$.foo ? ($ > $x)", {x: 2}, true)
# # jsonb_path_match(json, '$.foo ? ($ > $x)', '{"x":2}', true)
def path_match!(path, vars=nil, silent=nil)
Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_match, path, vars, silent))
end
# The same as #path_match!, except that timezone-aware conversions are used for date/time values.
def path_match_tz!(path, vars=nil, silent=nil)
Sequel::SQL::BooleanExpression.new(:NOOP, _path_function(:jsonb_path_match_tz, path, vars, silent))
end
# Returns a set of all jsonb values specified by the JSON path
# for the json object.
#
# json_op.path_query("$.foo")
# # jsonb_path_query(json, '$.foo')
#
# json_op.path_query("$.foo ? ($ > $x)", x: 2)
# # jsonb_path_query(json, '$.foo ? ($ > $x)', '{"x":2}')
#
# json_op.path_query("$.foo ? ($ > $x)", {x: 2}, true)
# # jsonb_path_query(json, '$.foo ? ($ > $x)', '{"x":2}', true)
def path_query(path, vars=nil, silent=nil)
_path_function(:jsonb_path_query, path, vars, silent)
end
# The same as #path_query, except that timezone-aware conversions are used for date/time values.
def path_query_tz(path, vars=nil, silent=nil)
_path_function(:jsonb_path_query_tz, path, vars, silent)
end
# Returns a jsonb array of all values specified by the JSON path
# for the json object.
#
# json_op.path_query_array("$.foo")
# # jsonb_path_query_array(json, '$.foo')
#
# json_op.path_query_array("$.foo ? ($ > $x)", x: 2)
# # jsonb_path_query_array(json, '$.foo ? ($ > $x)', '{"x":2}')
#
# json_op.path_query_array("$.foo ? ($ > $x)", {x: 2}, true)
# # jsonb_path_query_array(json, '$.foo ? ($ > $x)', '{"x":2}', true)
def path_query_array(path, vars=nil, silent=nil)
JSONBOp.new(_path_function(:jsonb_path_query_array, path, vars, silent))
end
# The same as #path_query_array, except that timezone-aware conversions are used for date/time values.
def path_query_array_tz(path, vars=nil, silent=nil)
JSONBOp.new(_path_function(:jsonb_path_query_array_tz, path, vars, silent))
end
# Returns the first item of the result specified by the JSON path
# for the json object.
#
# json_op.path_query_first("$.foo")
# # jsonb_path_query_first(json, '$.foo')
#
# json_op.path_query_first("$.foo ? ($ > $x)", x: 2)
# # jsonb_path_query_first(json, '$.foo ? ($ > $x)', '{"x":2}')
#
# json_op.path_query_first("$.foo ? ($ > $x)", {x: 2}, true)
# # jsonb_path_query_first(json, '$.foo ? ($ > $x)', '{"x":2}', true)
def path_query_first(path, vars=nil, silent=nil)
JSONBOp.new(_path_function(:jsonb_path_query_first, path, vars, silent))
end
# The same as #path_query_first, except that timezone-aware conversions are used for date/time values.
def path_query_first_tz(path, vars=nil, silent=nil)
JSONBOp.new(_path_function(:jsonb_path_query_first_tz, path, vars, silent))
end
# Return the receiver, since it is already a JSONBOp.
def pg_jsonb
self
end
# Return a pretty printed version of the receiver as a string expression.
#
# jsonb_op.pretty # jsonb_pretty(jsonb)
def pretty
Sequel::SQL::StringExpression.new(:NOOP, function(:pretty))
end
# Set the given jsonb value at the given path in the receiver.
# By default, this will create the value if it does not exist, but
# create_missing can be set to false to not create a new value.
#
# jsonb_op.set(['a', 'b'], h) # jsonb_set(jsonb, ARRAY['a', 'b'], h, true)
# jsonb_op.set(['a', 'b'], h, false) # jsonb_set(jsonb, ARRAY['a', 'b'], h, false)
def set(path, other, create_missing=true)
self.class.new(function(:set, wrap_input_array(path), wrap_input_jsonb(other), create_missing))
end
# The same as #set, except if +other+ is +nil+, then behaves according to +null_value_treatment+,
# which can be one of 'raise_exception', 'use_json_null' (default), 'delete_key', or 'return_target'.
def set_lax(path, other, create_missing=true, null_value_treatment='use_json_null')
self.class.new(function(:set_lax, wrap_input_array(path), wrap_input_jsonb(other), create_missing, null_value_treatment))
end
private
# Internals of the jsonb SQL/JSON path functions.
def _path_function(func, path, vars, silent)
args = []
if vars
if vars.is_a?(Hash)
vars = vars.to_json
end
args << vars
unless silent.nil?
args << silent
end
end
SQL::Function.new(func, self, path, *args)
end
# Return a placeholder literal with the given str and args, wrapped
# in a boolean expression, used by operators that return booleans.
def bool_op(str, other)
Sequel::SQL::BooleanExpression.new(:NOOP, Sequel::SQL::PlaceholderLiteralString.new(str, [value, other]))
end
# Wrap argument in a PGArray if it is an array
def wrap_input_array(obj)
if obj.is_a?(Array) && Sequel.respond_to?(:pg_array)
Sequel.pg_array(obj)
else
obj
end
end
# Wrap argument in a JSONBArray or JSONBHash if it is an array or hash.
def wrap_input_jsonb(obj)
if Sequel.respond_to?(:pg_jsonb) && (obj.is_a?(Array) || obj.is_a?(Hash))
Sequel.pg_jsonb(obj)
else
obj
end
end
# The jsonb type functions are prefixed with jsonb_
def function_name(name)
"jsonb_#{name}"
end
end
# Represents JSONB subscripts. This is abstracted because the
# subscript support depends on the database version.
class JSONBSubscriptOp < SQL::Expression
SUBSCRIPT = ["".freeze, "[".freeze, "]".freeze].freeze
# The expression being subscripted
attr_reader :expression
# The subscript to use
attr_reader :sub
# Set the expression and subscript to the given arguments
def initialize(expression, sub)
@expression = expression
@sub = sub
freeze
end
# Use subscripts instead of -> operator on PostgreSQL 14+
def to_s_append(ds, sql)
server_version = ds.db.server_version
frag = server_version && server_version >= 140000 ? SUBSCRIPT : JSONOp::GET
ds.literal_append(sql, Sequel::SQL::PlaceholderLiteralString.new(frag, [@expression, @sub]))
end
# Support transforming of jsonb subscripts
def sequel_ast_transform(transformer)
self.class.new(transformer.call(@expression), transformer.call(@sub))
end
end
module JSONOpMethods
# Wrap the receiver in an JSONOp so you can easily use the PostgreSQL
# json functions and operators with it.
def pg_json
JSONOp.new(self)
end
#
# Wrap the receiver in an JSONBOp so you can easily use the PostgreSQL
# jsonb functions and operators with it.
def pg_jsonb
JSONBOp.new(self)
end
end
# :nocov:
if defined?(JSONArray)
# :nocov:
class JSONArray
# Wrap the JSONArray instance in an JSONOp, allowing you to easily use
# the PostgreSQL json functions and operators with literal jsons.
def op
JSONOp.new(self)
end
end
class JSONHash
# Wrap the JSONHash instance in an JSONOp, allowing you to easily use
# the PostgreSQL json functions and operators with literal jsons.
def op
JSONOp.new(self)
end
end
class JSONBArray
# Wrap the JSONBArray instance in an JSONBOp, allowing you to easily use
# the PostgreSQL jsonb functions and operators with literal jsonbs.
def op
JSONBOp.new(self)
end
end
class JSONBHash
# Wrap the JSONBHash instance in an JSONBOp, allowing you to easily use
# the PostgreSQL jsonb functions and operators with literal jsonbs.
def op
JSONBOp.new(self)
end
end
end
end
module SQL::Builders
# Return the object wrapped in an Postgres::JSONOp.
def pg_json_op(v)
case v
when Postgres::JSONOp
v
else
Postgres::JSONOp.new(v)
end
end
# Return the object wrapped in an Postgres::JSONBOp.
def pg_jsonb_op(v)
case v
when Postgres::JSONBOp
v
else
Postgres::JSONBOp.new(v)
end
end
end
class SQL::GenericExpression
include Sequel::Postgres::JSONOpMethods
end
class LiteralString
include Sequel::Postgres::JSONOpMethods
end
end
# :nocov:
if Sequel.core_extensions?
class Symbol
include Sequel::Postgres::JSONOpMethods
end
end
if defined?(Sequel::CoreRefinements)
module Sequel::CoreRefinements
refine Symbol do
include Sequel::Postgres::JSONOpMethods
end
end
end
# :nocov: