module Sequel::Postgres::JSONDatabaseMethods
Methods enabling Database
object integration with the json type.
Attributes
Whether to typecast strings for json/jsonb types as JSON strings, instead of trying to parse the string as JSON. False by default.
Whether to wrap JSON primitives instead of using Ruby objects. Wrapping the primitives allows the primitive values to roundtrip, but it can cause problems, especially as false/null JSON values will be treated as truthy in Ruby due to the wrapping. False by default.
Public Class Methods
Deprecated
# File lib/sequel/extensions/pg_json.rb 233 def self.db_parse_json(s) 234 # SEQUEL6: Remove 235 parse_json(s) 236 rescue Sequel::InvalidValue 237 raise unless s.is_a?(String) 238 parse_json("[#{s}]").first 239 end
Deprecated
# File lib/sequel/extensions/pg_json.rb 242 def self.db_parse_jsonb(s) 243 # SEQUEL6: Remove 244 parse_json(s, true) 245 rescue Sequel::InvalidValue 246 raise unless s.is_a?(String) 247 parse_json("[#{s}]").first 248 end
# File lib/sequel/extensions/pg_json.rb 218 def self.extended(db) 219 db.instance_exec do 220 add_conversion_proc(114, method(:_db_parse_json)) 221 add_conversion_proc(3802, method(:_db_parse_jsonb)) 222 if respond_to?(:register_array_type) 223 register_array_type('json', :oid=>199, :scalar_oid=>114) 224 register_array_type('jsonb', :oid=>3807, :scalar_oid=>3802) 225 end 226 @schema_type_classes[:json] = [JSONObject] 227 @schema_type_classes[:jsonb] = [JSONBObject] 228 end 229 end
Deprecated
# File lib/sequel/extensions/pg_json.rb 251 def self.parse_json(s, jsonb=false) 252 # SEQUEL6: Remove 253 Sequel::Deprecation.deprecate("Sequel::Postgres::JSONDatabaseMethods.{parse_json,db_parse_json,db_parse_jsonb} are deprecated and will be removed in Sequel 6.") 254 begin 255 value = Sequel.parse_json(s) 256 rescue Sequel.json_parser_error_class => e 257 raise Sequel.convert_exception_class(e, Sequel::InvalidValue) 258 end 259 260 case value 261 when Array 262 (jsonb ? JSONBArray : JSONArray).new(value) 263 when Hash 264 (jsonb ? JSONBHash : JSONHash).new(value) 265 when String, Numeric, true, false, nil 266 value 267 else 268 raise Sequel::InvalidValue, "unhandled json value: #{value.inspect} (from #{s.inspect})" 269 end 270 end
Public Instance Methods
Handle json and jsonb types in bound variables
# File lib/sequel/extensions/pg_json.rb 285 def bound_variable_arg(arg, conn) 286 case arg 287 when JSONObject, JSONBObject 288 Sequel.object_to_json(arg) 289 else 290 super 291 end 292 end
Private Instance Methods
Parse JSON data coming from the database. Since PostgreSQL allows non JSON data in JSON fields (such as plain numbers and strings), we don't want to raise an exception for that.
# File lib/sequel/extensions/pg_json.rb 299 def _db_parse_json(s) 300 _wrap_json(_parse_json(s)) 301 rescue Sequel::InvalidValue 302 raise unless s.is_a?(String) 303 _wrap_json(_parse_json("[#{s}]").first) 304 end
Same as _db_parse_json
, but consider the input as jsonb.
# File lib/sequel/extensions/pg_json.rb 307 def _db_parse_jsonb(s) 308 _wrap_jsonb(_parse_json(s)) 309 rescue Sequel::InvalidValue 310 raise unless s.is_a?(String) 311 _wrap_jsonb(_parse_json("[#{s}]").first) 312 end
Parse the given string as json, returning either a JSONArray
or JSONHash
instance (or JSONBArray
or JSONBHash
instance if jsonb argument is true), or a String
, Numeric
, true, false, or nil if the json library used supports that.
# File lib/sequel/extensions/pg_json.rb 318 def _parse_json(s) 319 begin 320 Sequel.parse_json(s) 321 rescue Sequel.json_parser_error_class => e 322 raise Sequel.convert_exception_class(e, Sequel::InvalidValue) 323 end 324 end
Wrap the parsed JSON value in the appropriate JSON wrapper class. Only wrap primitive values if wrap_json_primitives
is set.
# File lib/sequel/extensions/pg_json.rb 328 def _wrap_json(value) 329 if klass = JSON_WRAPPER_MAPPING[value.class] 330 klass.new(value) 331 elsif klass = JSON_PRIMITIVE_WRAPPER_MAPPING[value.class] 332 if wrap_json_primitives 333 klass.new(value) 334 else 335 value 336 end 337 else 338 raise Sequel::InvalidValue, "unhandled json value: #{value.inspect}" 339 end 340 end
Wrap the parsed JSON value in the appropriate JSONB wrapper class. Only wrap primitive values if wrap_json_primitives
is set.
# File lib/sequel/extensions/pg_json.rb 344 def _wrap_jsonb(value) 345 if klass = JSONB_WRAPPER_MAPPING[value.class] 346 klass.new(value) 347 elsif klass = JSONB_PRIMITIVE_WRAPPER_MAPPING[value.class] 348 if wrap_json_primitives 349 klass.new(value) 350 else 351 value 352 end 353 else 354 raise Sequel::InvalidValue, "unhandled jsonb value: #{value.inspect}" 355 end 356 end
Handle json[] and jsonb[] types in bound variables.
# File lib/sequel/extensions/pg_json.rb 359 def bound_variable_array(a) 360 case a 361 when JSONObject, JSONBObject 362 "\"#{Sequel.object_to_json(a).gsub('"', '\\"')}\"" 363 else 364 super 365 end 366 end
Make the column type detection recognize the json types.
# File lib/sequel/extensions/pg_json.rb 369 def schema_column_type(db_type) 370 case db_type 371 when 'json' 372 :json 373 when 'jsonb' 374 :jsonb 375 else 376 super 377 end 378 end
Set the :callable_default value if the default value is recognized as an empty json/jsonb array/hash.
# File lib/sequel/extensions/pg_json.rb 381 def schema_post_process(_) 382 super.each do |a| 383 h = a[1] 384 if (h[:type] == :json || h[:type] == :jsonb) && h[:default] =~ /\A'(\{\}|\[\])'::jsonb?\z/ 385 is_array = $1 == '[]' 386 387 klass = if h[:type] == :json 388 if is_array 389 JSONArray 390 else 391 JSONHash 392 end 393 elsif is_array 394 JSONBArray 395 else 396 JSONBHash 397 end 398 399 h[:callable_default] = lambda{klass.new(is_array ? [] : {})} 400 end 401 end 402 end
Convert the value given to a JSON wrapper object.
# File lib/sequel/extensions/pg_json.rb 405 def typecast_value_json(value) 406 case value 407 when JSONObject 408 value 409 when String 410 if typecast_json_strings 411 JSONString.new(value) 412 else 413 _wrap_json(_parse_json(value)) 414 end 415 when *JSON_WRAP_CLASSES 416 JSON_COMBINED_WRAPPER_MAPPING[value.class].new(value) 417 when JSONBObject 418 value = value.__getobj__ 419 JSON_COMBINED_WRAPPER_MAPPING[value.class].new(value) 420 else 421 raise Sequel::InvalidValue, "invalid value for json: #{value.inspect}" 422 end 423 end
Convert the value given to a JSONB wrapper object.
# File lib/sequel/extensions/pg_json.rb 426 def typecast_value_jsonb(value) 427 case value 428 when JSONBObject 429 value 430 when String 431 if typecast_json_strings 432 JSONBString.new(value) 433 else 434 _wrap_jsonb(_parse_json(value)) 435 end 436 when *JSONB_WRAP_CLASSES 437 JSONB_COMBINED_WRAPPER_MAPPING[value.class].new(value) 438 when JSONObject 439 value = value.__getobj__ 440 JSONB_COMBINED_WRAPPER_MAPPING[value.class].new(value) 441 else 442 raise Sequel::InvalidValue, "invalid value for jsonb: #{value.inspect}" 443 end 444 end