associate_jsonb 0.0.1 → 0.0.7
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/README.md +81 -1
- data/lib/associate_jsonb.rb +111 -1
- data/lib/associate_jsonb/arel_extensions/nodes/binary.rb +14 -0
- data/lib/associate_jsonb/arel_extensions/nodes/table_alias.rb +38 -0
- data/lib/associate_jsonb/arel_extensions/table.rb +40 -0
- data/lib/associate_jsonb/arel_extensions/visitors/postgresql.rb +113 -0
- data/lib/associate_jsonb/arel_extensions/visitors/visitor.rb +19 -0
- data/lib/associate_jsonb/arel_nodes/jsonb/attribute.rb +38 -0
- data/lib/associate_jsonb/arel_nodes/sql_casted_binary.rb +20 -0
- data/lib/associate_jsonb/arel_nodes/sql_casted_equality.rb +26 -12
- data/lib/associate_jsonb/associations/alias_tracker.rb +13 -0
- data/lib/associate_jsonb/associations/association_scope.rb +18 -45
- data/lib/associate_jsonb/associations/belongs_to_association.rb +8 -8
- data/lib/associate_jsonb/associations/builder/belongs_to.rb +5 -3
- data/lib/associate_jsonb/associations/join_dependency.rb +21 -0
- data/lib/associate_jsonb/attribute_methods.rb +19 -0
- data/lib/associate_jsonb/attribute_methods/read.rb +15 -0
- data/lib/associate_jsonb/connection_adapters/schema_creation.rb +162 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/add_jsonb_foreign_key_function.rb +9 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/add_jsonb_nested_set_function.rb +9 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/alter_table.rb +40 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/constraint_definition.rb +60 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/reference_definition.rb +88 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/table.rb +12 -0
- data/lib/associate_jsonb/connection_adapters/schema_definitions/table_definition.rb +25 -0
- data/lib/associate_jsonb/connection_adapters/schema_statements.rb +116 -0
- data/lib/associate_jsonb/persistence.rb +14 -0
- data/lib/associate_jsonb/predicate_builder.rb +15 -0
- data/lib/associate_jsonb/reflection.rb +2 -2
- data/lib/associate_jsonb/relation/where_clause.rb +19 -0
- data/lib/associate_jsonb/supported_rails_version.rb +6 -0
- data/lib/associate_jsonb/version.rb +1 -1
- data/lib/associate_jsonb/with_store_attribute.rb +59 -23
- metadata +39 -14
- data/lib/associate_jsonb/arel_node_extensions/binary.rb +0 -12
- data/lib/associate_jsonb/connection_adapters/reference_definition.rb +0 -64
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module AssociateJsonb
|
5
|
+
module ArelExtensions
|
6
|
+
module Visitors
|
7
|
+
module Visitor
|
8
|
+
def dispatch_cache
|
9
|
+
@dispatch_cache ||= Hash.new do |hash, klass|
|
10
|
+
hash[klass] =
|
11
|
+
"visit_#{(klass.name || '').
|
12
|
+
sub("AssociateJsonb::ArelNodes::SqlCasted", "Arel::Nodes::").
|
13
|
+
gsub('::', '_')}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module AssociateJsonb
|
5
|
+
module ArelNodes
|
6
|
+
module Jsonb
|
7
|
+
class Attribute
|
8
|
+
attr_reader :relation, :name, :delegated
|
9
|
+
|
10
|
+
def initialize(relation, name, delegated)
|
11
|
+
@relation = relation,
|
12
|
+
@name = name
|
13
|
+
@delegated = delegated
|
14
|
+
end
|
15
|
+
|
16
|
+
def lower
|
17
|
+
relation.lower self
|
18
|
+
end
|
19
|
+
|
20
|
+
def type_cast_for_database(value)
|
21
|
+
relation.type_cast_for_database(name, value)
|
22
|
+
end
|
23
|
+
|
24
|
+
def able_to_type_cast?
|
25
|
+
relation.able_to_type_cast?
|
26
|
+
end
|
27
|
+
|
28
|
+
def respond_to_missing?(mthd, include_private = false)
|
29
|
+
delegated.respond_to?(mthd, include_private)
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(mthd, *args, **opts, &block)
|
33
|
+
delegated.public_send(mthd, *args, **opts, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module AssociateJsonb
|
5
|
+
module ArelNodes
|
6
|
+
class SqlCastedBinary < ::Arel::Nodes::Binary
|
7
|
+
attr_reader :original_left
|
8
|
+
def initialize(left, cast_as, right)
|
9
|
+
@original_left = left
|
10
|
+
super(
|
11
|
+
::Arel::Nodes::NamedFunction.new(
|
12
|
+
"CAST",
|
13
|
+
[ left.as(cast_as) ]
|
14
|
+
),
|
15
|
+
right
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,20 +1,34 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
# module AssociateJsonb
|
5
|
+
# module ArelNodes
|
6
|
+
# class SqlCastedEquality < ::Arel::Nodes::Equality
|
7
|
+
# attr_reader :original_left
|
8
|
+
# def initialize(left, cast_as, right)
|
9
|
+
# @original_left = left
|
10
|
+
# super(
|
11
|
+
# ::Arel::Nodes::NamedFunction.new(
|
12
|
+
# "CAST",
|
13
|
+
# [ left.as(cast_as) ]
|
14
|
+
# ),
|
15
|
+
# right
|
16
|
+
# )
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
|
23
|
+
# encoding: utf-8
|
24
|
+
# frozen_string_literal: true
|
25
|
+
|
4
26
|
module AssociateJsonb
|
5
27
|
module ArelNodes
|
6
|
-
class SqlCastedEquality < ::
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
super(
|
11
|
-
::Arel::Nodes::NamedFunction.new(
|
12
|
-
"CAST",
|
13
|
-
[ left.as(cast_as) ]
|
14
|
-
),
|
15
|
-
right
|
16
|
-
)
|
17
|
-
end
|
28
|
+
class SqlCastedEquality < AssociateJsonb::ArelNodes::SqlCastedBinary
|
29
|
+
def operator; :== end
|
30
|
+
alias :operand1 :left
|
31
|
+
alias :operand2 :right
|
18
32
|
end
|
19
33
|
end
|
20
34
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/conversions"
|
4
|
+
|
5
|
+
module AssociateJsonb
|
6
|
+
module Associations
|
7
|
+
module AliasTracker # :nodoc:
|
8
|
+
def aliased_table_for(table_name, aliased_name, type_caster, store_tracker = nil)
|
9
|
+
super(table_name, aliased_name, type_caster).with_store_tracker(store_tracker)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -4,6 +4,22 @@
|
|
4
4
|
module AssociateJsonb
|
5
5
|
module Associations
|
6
6
|
module AssociationScope #:nodoc:
|
7
|
+
|
8
|
+
def get_chain(reflection, association, tracker)
|
9
|
+
name = reflection.name
|
10
|
+
chain = [ActiveRecord::Reflection::RuntimeReflection.new(reflection, association)]
|
11
|
+
reflection.chain.drop(1).each do |refl|
|
12
|
+
aliased_table = tracker.aliased_table_for(
|
13
|
+
refl.table_name,
|
14
|
+
refl.alias_candidate(name),
|
15
|
+
refl.klass.type_caster,
|
16
|
+
refl.klass.store_column_attribute_tracker
|
17
|
+
)
|
18
|
+
chain << ActiveRecord::Associations::AssociationScope::ReflectionProxy.new(refl, aliased_table)
|
19
|
+
end
|
20
|
+
chain
|
21
|
+
end
|
22
|
+
|
7
23
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
8
24
|
def last_chain_scope(scope, owner_reflection, owner)
|
9
25
|
reflection = owner_reflection.instance_variable_get(:@reflection)
|
@@ -28,40 +44,21 @@ module AssociateJsonb
|
|
28
44
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
29
45
|
|
30
46
|
def apply_jsonb_equality(scope, table, jsonb_column, store_key, foreign_key, value, foreign_klass)
|
31
|
-
sql_type = type =
|
47
|
+
sql_type = type = nil
|
32
48
|
begin
|
33
49
|
type = foreign_klass.attribute_types[foreign_key.to_s]
|
34
50
|
raise "type not found" unless type.present?
|
35
51
|
sql_type = foreign_klass.columns_hash[foreign_key.to_s]
|
36
52
|
raise "not a column" unless sql_type.present?
|
37
53
|
sql_type = sql_type.sql_type
|
38
|
-
node_klass = Arel::Nodes::Jsonb::DashArrow
|
39
54
|
rescue
|
40
55
|
type = ActiveModel::Type::String.new
|
41
56
|
sql_type = "text"
|
42
|
-
node_klass = Arel::Nodes::Jsonb::DashDoubleArrow
|
43
57
|
end
|
44
58
|
|
45
|
-
# scope.where!(
|
46
|
-
# Arel::Nodes::HashableNamedFunction.new(
|
47
|
-
# "CAST",
|
48
|
-
# [
|
49
|
-
# node_klass.
|
50
|
-
# new(table, table[jsonb_column], store_key).
|
51
|
-
# as(sql_type)
|
52
|
-
# ]
|
53
|
-
# ).eq(
|
54
|
-
# Arel::Nodes::BindParam.new(
|
55
|
-
# ActiveRecord::Relation::QueryAttribute.new(
|
56
|
-
# store_key, value, type
|
57
|
-
# )
|
58
|
-
# )
|
59
|
-
# )
|
60
|
-
# )
|
61
|
-
|
62
59
|
scope.where!(
|
63
60
|
Arel::Nodes::SqlCastedEquality.new(
|
64
|
-
|
61
|
+
Arel::Nodes::Jsonb::DashDoubleArrow.new(table, table[jsonb_column], store_key),
|
65
62
|
sql_type,
|
66
63
|
Arel::Nodes::BindParam.new(
|
67
64
|
ActiveRecord::Relation::QueryAttribute.new(
|
@@ -70,30 +67,6 @@ module AssociateJsonb
|
|
70
67
|
)
|
71
68
|
)
|
72
69
|
)
|
73
|
-
|
74
|
-
# scope.where!(
|
75
|
-
# Arel::Nodes::Jsonb::DashDoubleArrow.
|
76
|
-
# new(table, table[jsonb_column], store_key).
|
77
|
-
# eq(
|
78
|
-
# Arel::Nodes::BindParam.new(
|
79
|
-
# ActiveRecord::Relation::QueryAttribute.new(
|
80
|
-
# store_key, value, ActiveModel::Type::String.new
|
81
|
-
# )
|
82
|
-
# )
|
83
|
-
# )
|
84
|
-
# )
|
85
|
-
|
86
|
-
# scope.where!(
|
87
|
-
# node_klass.new(
|
88
|
-
# table, table[jsonb_column], store_key
|
89
|
-
# ).eq(
|
90
|
-
# Arel::Nodes::BindParam.new(
|
91
|
-
# ActiveRecord::Relation::QueryAttribute.new(
|
92
|
-
# store_key, value, type
|
93
|
-
# )
|
94
|
-
# )
|
95
|
-
# )
|
96
|
-
# )
|
97
70
|
end
|
98
71
|
end
|
99
72
|
end
|
@@ -4,14 +4,14 @@
|
|
4
4
|
module AssociateJsonb
|
5
5
|
module Associations
|
6
6
|
module BelongsToAssociation #:nodoc:
|
7
|
-
def replace_keys(record)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
7
|
+
# def replace_keys(record)
|
8
|
+
# return super unless reflection.options.key?(:store)
|
9
|
+
#
|
10
|
+
# owner[reflection.foreign_key] =
|
11
|
+
# record._read_attribute(
|
12
|
+
# reflection.association_primary_key(record.class)
|
13
|
+
# )
|
14
|
+
# end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -22,7 +22,7 @@ module AssociateJsonb
|
|
22
22
|
key = (reflection.jsonb_store_key || foreign_key).to_s
|
23
23
|
store = reflection.jsonb_store_attr
|
24
24
|
|
25
|
-
mixin.instance_eval
|
25
|
+
mixin.instance_eval <<~CODE, __FILE__, __LINE__ + 1
|
26
26
|
if attribute_names.include?(foreign_key)
|
27
27
|
raise AssociateJsonb::Associations::
|
28
28
|
ConflictingAssociation,
|
@@ -33,6 +33,7 @@ module AssociateJsonb
|
|
33
33
|
|
34
34
|
opts = {}
|
35
35
|
foreign_type = :integer
|
36
|
+
sql_type = "numeric"
|
36
37
|
begin
|
37
38
|
primary_key = reflection.active_record_primary_key.to_s
|
38
39
|
primary_column = reflection.klass.columns.find {|col| col.name == primary_key }
|
@@ -40,6 +41,7 @@ module AssociateJsonb
|
|
40
41
|
if primary_column
|
41
42
|
foreign_type = primary_column.type
|
42
43
|
sql_data = primary_column.sql_type_metadata.as_json
|
44
|
+
sql_type = sql_data["sql_type"]
|
43
45
|
%i[ limit precision scale ].each do |k|
|
44
46
|
opts[k] = sql_data[k.to_s] if sql_data[k.to_s]
|
45
47
|
end
|
@@ -49,8 +51,8 @@ module AssociateJsonb
|
|
49
51
|
foreign_type = :integer
|
50
52
|
end
|
51
53
|
|
52
|
-
mixin.instance_eval
|
53
|
-
store_column_attribute(:#{store}, :#{foreign_key},
|
54
|
+
mixin.instance_eval <<~CODE, __FILE__, __LINE__ + 1
|
55
|
+
store_column_attribute(:#{store}, :#{foreign_key}, foreign_type, sql_type: sql_type, key: "#{key}", **opts)
|
54
56
|
CODE
|
55
57
|
end
|
56
58
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/conversions"
|
4
|
+
|
5
|
+
module AssociateJsonb
|
6
|
+
module Associations
|
7
|
+
module JoinDependency # :nodoc:
|
8
|
+
private
|
9
|
+
def table_aliases_for(parent, node)
|
10
|
+
node.reflection.chain.map { |reflection|
|
11
|
+
alias_tracker.aliased_table_for(
|
12
|
+
reflection.table_name,
|
13
|
+
table_alias_for(reflection, parent, reflection != node.reflection),
|
14
|
+
reflection.klass.type_caster,
|
15
|
+
reflection.klass.store_column_attribute_tracker
|
16
|
+
)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module AssociateJsonb
|
5
|
+
module AttributeMethods
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include Read
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def attributes_with_info(attribute_names)
|
14
|
+
attribute_names.each_with_object({}) do |name, attrs|
|
15
|
+
attrs[name] = _fetch_attribute(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module AssociateJsonb
|
5
|
+
module AttributeMethods
|
6
|
+
module Read
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def _fetch_attribute(attr_name, &block) # :nodoc
|
10
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
11
|
+
@attributes.fetch(attr_name.to_s, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module AssociateJsonb
|
5
|
+
module ConnectionAdapters
|
6
|
+
module SchemaCreation
|
7
|
+
private
|
8
|
+
def visit_AlterTable(o)
|
9
|
+
sql = super
|
10
|
+
sql << o.constraint_adds.map {|ct| visit_AddConstraint ct }.join(" ")
|
11
|
+
sql << o.constraint_drops.map {|ct| visit_DropConstraint ct }.join(" ")
|
12
|
+
sql
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_TableDefinition(o)
|
16
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
17
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
18
|
+
create_sql << "#{quote_table_name(o.name)} "
|
19
|
+
|
20
|
+
statements = o.columns.map { |c| accept c }
|
21
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
22
|
+
|
23
|
+
if supports_indexes_in_create?
|
24
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
25
|
+
end
|
26
|
+
|
27
|
+
if supports_foreign_keys?
|
28
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
29
|
+
# statements.concat(o.constraints.map { |ct| visit_ConstraintDefinition(ct) })
|
30
|
+
end
|
31
|
+
|
32
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
33
|
+
add_table_options!(create_sql, table_options(o))
|
34
|
+
create_sql << " AS #{to_sql(o.as)}" if o.as
|
35
|
+
create_sql
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_ConstraintDeferral(o)
|
39
|
+
return "" unless o.deferrable_default?
|
40
|
+
return "NOT DEFERRABLE" unless o.deferrable?
|
41
|
+
initial =
|
42
|
+
case o.deferrable
|
43
|
+
when :immediate
|
44
|
+
"IMMEDIATE"
|
45
|
+
else
|
46
|
+
"DEFERRED"
|
47
|
+
end
|
48
|
+
"DEFERRABLE INITIALLY #{initial}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_ConstraintDefinition(o)
|
52
|
+
+<<-SQL.squish
|
53
|
+
CONSTRAINT #{quote_column_name(o.name)}
|
54
|
+
CHECK (#{o.value})
|
55
|
+
#{visit_ConstraintDeferral(o)}
|
56
|
+
#{o.not_valid? ? "NOT VALID" : ''}
|
57
|
+
SQL
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit_AddConstraint(o)
|
61
|
+
sql = +""
|
62
|
+
if o.force?
|
63
|
+
sql << visit_DropConstraint(o)
|
64
|
+
sql << " "
|
65
|
+
end
|
66
|
+
sql << "ADD #{accept(o)}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def visit_DropConstraint(o, if_exists: false)
|
70
|
+
+<<-SQL.squish
|
71
|
+
DROP CONSTRAINT #{quote_column_name(o.name)}
|
72
|
+
#{o.force? ? "IF EXISTS" : ""}
|
73
|
+
SQL
|
74
|
+
end
|
75
|
+
|
76
|
+
def visit_AddJsonbForeignKeyFunction(*)
|
77
|
+
<<~SQL
|
78
|
+
CREATE OR REPLACE FUNCTION jsonb_foreign_key
|
79
|
+
(
|
80
|
+
table_name text,
|
81
|
+
foreign_key text,
|
82
|
+
store jsonb,
|
83
|
+
key text,
|
84
|
+
type text default 'numeric',
|
85
|
+
nullable boolean default TRUE
|
86
|
+
)
|
87
|
+
RETURNS BOOLEAN AS
|
88
|
+
$BODY$
|
89
|
+
DECLARE
|
90
|
+
does_exist BOOLEAN;
|
91
|
+
BEGIN
|
92
|
+
IF store->key IS NULL
|
93
|
+
THEN
|
94
|
+
return nullable;
|
95
|
+
END IF;
|
96
|
+
|
97
|
+
EXECUTE FORMAT('SELECT EXISTS (SELECT 1 FROM %1$I WHERE %1$I.%2$I = CAST($1 AS ' || type || '))', table_name, foreign_key)
|
98
|
+
INTO does_exist
|
99
|
+
USING store->>key;
|
100
|
+
|
101
|
+
RETURN does_exist;
|
102
|
+
END;
|
103
|
+
$BODY$
|
104
|
+
LANGUAGE plpgsql;
|
105
|
+
|
106
|
+
SQL
|
107
|
+
end
|
108
|
+
|
109
|
+
def visit_AddJsonbNestedSetFunction(*)
|
110
|
+
<<~SQL
|
111
|
+
CREATE OR REPLACE FUNCTION jsonb_nested_set
|
112
|
+
(
|
113
|
+
target jsonb,
|
114
|
+
path text[],
|
115
|
+
new_value jsonb
|
116
|
+
)
|
117
|
+
RETURNS jsonb AS
|
118
|
+
$BODY$
|
119
|
+
DECLARE
|
120
|
+
new_json jsonb := '{}'::jsonb;
|
121
|
+
does_exist BOOLEAN;
|
122
|
+
current_path text[];
|
123
|
+
key text;
|
124
|
+
BEGIN
|
125
|
+
IF target #> path IS NOT NULL
|
126
|
+
THEN
|
127
|
+
return jsonb_set(target, path, new_value);
|
128
|
+
ELSE
|
129
|
+
new_json := target;
|
130
|
+
|
131
|
+
IF array_length(path, 1) > 1
|
132
|
+
THEN
|
133
|
+
FOREACH key IN ARRAY path[:(array_length(path, 1) - 1)]
|
134
|
+
LOOP
|
135
|
+
current_path := array_append(current_path, key);
|
136
|
+
IF new_json #> current_path IS NULL
|
137
|
+
THEN
|
138
|
+
new_json := jsonb_set(new_json, current_path, '{}'::jsonb, TRUE);
|
139
|
+
END IF;
|
140
|
+
END LOOP;
|
141
|
+
END IF;
|
142
|
+
|
143
|
+
return jsonb_set(new_json, path, new_value, TRUE);
|
144
|
+
END IF;
|
145
|
+
END;
|
146
|
+
$BODY$
|
147
|
+
LANGUAGE plpgsql;
|
148
|
+
SQL
|
149
|
+
end
|
150
|
+
|
151
|
+
def add_column_options!(sql, opts)
|
152
|
+
super
|
153
|
+
|
154
|
+
if opts[:constraint]
|
155
|
+
sql << " #{accept(ConstraintDefinition.new(**opts[:constraint]))}"
|
156
|
+
end
|
157
|
+
|
158
|
+
sql
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|