rom-sql 3.0.1 → 3.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +428 -297
- data/LICENSE +20 -0
- data/README.md +14 -56
- data/lib/rom-sql.rb +2 -0
- data/lib/rom/plugins/relation/sql/auto_restrictions.rb +2 -0
- data/lib/rom/plugins/relation/sql/instrumentation.rb +2 -0
- data/lib/rom/plugins/relation/sql/postgres/explain.rb +6 -7
- data/lib/rom/plugins/relation/sql/postgres/full_text_search.rb +53 -0
- data/lib/rom/plugins/relation/sql/postgres/streaming.rb +97 -0
- data/lib/rom/sql.rb +2 -0
- data/lib/rom/sql/associations.rb +2 -0
- data/lib/rom/sql/associations/core.rb +10 -0
- data/lib/rom/sql/associations/many_to_many.rb +3 -1
- data/lib/rom/sql/associations/many_to_one.rb +2 -0
- data/lib/rom/sql/associations/one_to_many.rb +2 -0
- data/lib/rom/sql/associations/one_to_one.rb +2 -0
- data/lib/rom/sql/associations/one_to_one_through.rb +2 -0
- data/lib/rom/sql/associations/self_ref.rb +2 -0
- data/lib/rom/sql/attribute.rb +31 -22
- data/lib/rom/sql/attribute_aliasing.rb +88 -0
- data/lib/rom/sql/attribute_wrapping.rb +30 -0
- data/lib/rom/sql/commands.rb +2 -0
- data/lib/rom/sql/commands/create.rb +2 -0
- data/lib/rom/sql/commands/delete.rb +2 -0
- data/lib/rom/sql/commands/error_wrapper.rb +2 -0
- data/lib/rom/sql/commands/update.rb +2 -0
- data/lib/rom/sql/dsl.rb +11 -3
- data/lib/rom/sql/error.rb +2 -0
- data/lib/rom/sql/errors.rb +2 -0
- data/lib/rom/sql/extensions.rb +2 -0
- data/lib/rom/sql/extensions/active_support_notifications.rb +2 -0
- data/lib/rom/sql/extensions/mysql.rb +2 -0
- data/lib/rom/sql/extensions/mysql/type_builder.rb +2 -0
- data/lib/rom/sql/extensions/postgres.rb +3 -0
- data/lib/rom/sql/extensions/postgres/commands.rb +3 -1
- data/lib/rom/sql/extensions/postgres/type_builder.rb +6 -4
- data/lib/rom/sql/extensions/postgres/type_serializer.rb +2 -0
- data/lib/rom/sql/extensions/postgres/types.rb +2 -0
- data/lib/rom/sql/extensions/postgres/types/array.rb +7 -6
- data/lib/rom/sql/extensions/postgres/types/array_types.rb +3 -1
- data/lib/rom/sql/extensions/postgres/types/geometric.rb +2 -0
- data/lib/rom/sql/extensions/postgres/types/json.rb +76 -19
- data/lib/rom/sql/extensions/postgres/types/ltree.rb +25 -23
- data/lib/rom/sql/extensions/postgres/types/network.rb +2 -0
- data/lib/rom/sql/extensions/postgres/types/range.rb +2 -0
- data/lib/rom/sql/extensions/rails_log_subscriber.rb +2 -0
- data/lib/rom/sql/extensions/sqlite.rb +2 -0
- data/lib/rom/sql/extensions/sqlite/type_builder.rb +2 -0
- data/lib/rom/sql/extensions/sqlite/types.rb +2 -0
- data/lib/rom/sql/foreign_key.rb +3 -1
- data/lib/rom/sql/function.rb +38 -6
- data/lib/rom/sql/gateway.rb +9 -1
- data/lib/rom/sql/group_dsl.rb +2 -0
- data/lib/rom/sql/index.rb +2 -0
- data/lib/rom/sql/join_dsl.rb +2 -0
- data/lib/rom/sql/mapper_compiler.rb +12 -1
- data/lib/rom/sql/migration.rb +5 -3
- data/lib/rom/sql/migration/inline_runner.rb +2 -0
- data/lib/rom/sql/migration/migrator.rb +4 -2
- data/lib/rom/sql/migration/recorder.rb +2 -0
- data/lib/rom/sql/migration/runner.rb +4 -2
- data/lib/rom/sql/migration/schema_diff.rb +2 -0
- data/lib/rom/sql/migration/template.rb +2 -0
- data/lib/rom/sql/migration/writer.rb +12 -4
- data/lib/rom/sql/order_dsl.rb +2 -0
- data/lib/rom/sql/plugin/associates.rb +4 -2
- data/lib/rom/sql/plugin/nullify.rb +37 -0
- data/lib/rom/sql/plugin/pagination.rb +2 -0
- data/lib/rom/sql/plugins.rb +4 -0
- data/lib/rom/sql/projection_dsl.rb +3 -1
- data/lib/rom/sql/rake_task.rb +2 -0
- data/lib/rom/sql/relation.rb +3 -1
- data/lib/rom/sql/relation/reading.rb +32 -6
- data/lib/rom/sql/relation/writing.rb +2 -0
- data/lib/rom/sql/restriction_dsl.rb +9 -1
- data/lib/rom/sql/schema.rb +16 -2
- data/lib/rom/sql/schema/attributes_inferrer.rb +5 -3
- data/lib/rom/sql/schema/dsl.rb +3 -1
- data/lib/rom/sql/schema/index_dsl.rb +5 -2
- data/lib/rom/sql/schema/inferrer.rb +12 -8
- data/lib/rom/sql/schema/type_builder.rb +4 -2
- data/lib/rom/sql/spec/support.rb +5 -3
- data/lib/rom/sql/tasks/migration_tasks.rake +16 -11
- data/lib/rom/sql/transaction.rb +2 -0
- data/lib/rom/sql/type_dsl.rb +2 -0
- data/lib/rom/sql/type_extensions.rb +4 -4
- data/lib/rom/sql/type_serializer.rb +2 -0
- data/lib/rom/sql/types.rb +2 -0
- data/lib/rom/sql/version.rb +3 -1
- data/lib/rom/sql/wrap.rb +2 -0
- data/lib/rom/types/values.rb +2 -0
- metadata +34 -32
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module SQL
|
5
|
+
# @api private
|
6
|
+
module AttributeAliasing
|
7
|
+
# Return a new attribute with an alias
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# users[:id].aliased(:user_id)
|
11
|
+
#
|
12
|
+
# @return [SQL::Attribute]
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def aliased(alias_name)
|
16
|
+
new_name, new_alias_name = extract_alias_names(alias_name)
|
17
|
+
|
18
|
+
super(new_alias_name).with(name: new_name).meta(
|
19
|
+
sql_expr: alias_sql_expr(sql_expr, new_alias_name)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
alias as aliased
|
23
|
+
|
24
|
+
|
25
|
+
# Return true if this attribute is an aliased projection
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# class Tasks < ROM::Relation[:memory]
|
29
|
+
# schema do
|
30
|
+
# attribute :user_id, Types::Integer, alias: :id
|
31
|
+
# attribute :name, Types::String
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Users.schema[:user_id].aliased?
|
36
|
+
# # => true
|
37
|
+
# Users.schema[:user_id].aliased_projection?
|
38
|
+
# # => false
|
39
|
+
#
|
40
|
+
# Users.schema[:user_id].qualified_projection.aliased?
|
41
|
+
# # => true
|
42
|
+
# Users.schema[:user_id].qualified_projection.aliased_projection?
|
43
|
+
# # => true
|
44
|
+
#
|
45
|
+
# @return [TrueClass,FalseClass]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
def aliased_projection?
|
49
|
+
self.meta[:sql_expr].is_a?(Sequel::SQL::AliasedExpression)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
def alias_sql_expr(sql_expr, new_alias)
|
56
|
+
case sql_expr
|
57
|
+
when Sequel::SQL::AliasedExpression
|
58
|
+
Sequel::SQL::AliasedExpression.new(sql_expr.expression, new_alias, sql_expr.columns)
|
59
|
+
else
|
60
|
+
sql_expr.as(new_alias)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def extract_alias_names(alias_name)
|
66
|
+
new_name, new_alias_name = nil
|
67
|
+
|
68
|
+
if wrapped? && aliased?
|
69
|
+
# If the attribute is wrapped *and* aliased, make sure that we name the
|
70
|
+
# attribute in a way that will map the the requested alias name.
|
71
|
+
# Without this, the attribute will silently ignore the requested alias
|
72
|
+
# name and default to the pre-existing name.
|
73
|
+
new_name = "#{meta[:wrapped]}_#{options[:alias]}".to_sym
|
74
|
+
|
75
|
+
# Essentially, this makes it so "wrapped" attributes aren't true
|
76
|
+
# aliases, in that we actually alias the wrapped attribute, we use
|
77
|
+
# the old alias.
|
78
|
+
new_alias_name = options[:alias]
|
79
|
+
else
|
80
|
+
new_name = name || alias_name
|
81
|
+
new_alias_name = alias_name
|
82
|
+
end
|
83
|
+
|
84
|
+
[new_name, new_alias_name]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module SQL
|
5
|
+
# @api private
|
6
|
+
module AttributeWrapping
|
7
|
+
# Return if the attribute type is from a wrapped relation
|
8
|
+
#
|
9
|
+
# Wrapped attributes are used when two schemas from different relations
|
10
|
+
# are merged together. This way we can identify them easily and handle
|
11
|
+
# correctly in places like auto-mapping.
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
def wrapped?
|
15
|
+
!meta[:wrapped].nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return attribute type wrapped for the specified relation name
|
19
|
+
#
|
20
|
+
# @param [Symbol] name The name of the source relation (defaults to source.dataset)
|
21
|
+
#
|
22
|
+
# @return [Attribute]
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
def wrapped(name = source.dataset)
|
26
|
+
meta(wrapped: name).prefixed(name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/rom/sql/commands.rb
CHANGED
data/lib/rom/sql/dsl.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'concurrent/map'
|
2
4
|
require 'rom/support/inflector'
|
3
5
|
require 'rom/constants'
|
@@ -27,7 +29,13 @@ module ROM
|
|
27
29
|
|
28
30
|
# @api private
|
29
31
|
def call(&block)
|
30
|
-
|
32
|
+
arg, kwargs = select_relations(block.parameters)
|
33
|
+
|
34
|
+
if kwargs.nil?
|
35
|
+
result = instance_exec(arg, &block)
|
36
|
+
else
|
37
|
+
result = instance_exec(**kwargs, &block)
|
38
|
+
end
|
31
39
|
|
32
40
|
if result.is_a?(::Array)
|
33
41
|
result
|
@@ -82,9 +90,9 @@ module ROM
|
|
82
90
|
keys = parameters.select { |type, _| type == :keyreq }
|
83
91
|
|
84
92
|
if keys.empty?
|
85
|
-
relations
|
93
|
+
[relations, nil]
|
86
94
|
else
|
87
|
-
keys.each_with_object({}) { |(_, k), rs| rs[k] = relations[k] }
|
95
|
+
[nil, keys.each_with_object({}) { |(_, k), rs| rs[k] = relations[k] }]
|
88
96
|
end
|
89
97
|
end
|
90
98
|
end
|
data/lib/rom/sql/error.rb
CHANGED
data/lib/rom/sql/errors.rb
CHANGED
data/lib/rom/sql/extensions.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rom/sql/extensions/postgres/commands'
|
2
4
|
require 'rom/sql/extensions/postgres/types'
|
3
5
|
require 'rom/sql/extensions/postgres/type_builder'
|
4
6
|
require 'rom/sql/extensions/postgres/type_serializer'
|
5
7
|
require 'rom/plugins/relation/sql/postgres/explain'
|
8
|
+
require 'rom/plugins/relation/sql/postgres/full_text_search'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rom/sql/commands/create'
|
2
4
|
require 'rom/sql/commands/update'
|
3
5
|
|
@@ -15,7 +17,7 @@ module ROM
|
|
15
17
|
#
|
16
18
|
# @api private
|
17
19
|
def returning_dataset
|
18
|
-
relation.dataset.returning(*relation.
|
20
|
+
relation.dataset.returning(*relation.schema.qualified_projection)
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ROM
|
2
4
|
module SQL
|
3
5
|
module Postgres
|
4
6
|
class TypeBuilder < Schema::TypeBuilder
|
5
7
|
defines :db_numeric_types, :db_type_mapping, :db_array_type_matcher
|
6
8
|
|
7
|
-
db_numeric_types %w
|
9
|
+
db_numeric_types %w[
|
8
10
|
smallint integer bigint
|
9
11
|
decimal numeric real
|
10
12
|
double\ precision serial bigserial
|
11
|
-
|
13
|
+
].to_set.freeze
|
12
14
|
|
13
15
|
db_type_mapping(
|
14
16
|
'uuid' => Types::UUID,
|
@@ -39,11 +41,11 @@ module ROM
|
|
39
41
|
|
40
42
|
db_array_type_matcher '[]'.freeze
|
41
43
|
|
42
|
-
def map_pk_type(type, db_type, options
|
44
|
+
def map_pk_type(type, db_type, **options)
|
43
45
|
if numeric?(type, db_type)
|
44
46
|
type = self.class.numeric_pk_type
|
45
47
|
else
|
46
|
-
type = map_type(type, db_type, options)
|
48
|
+
type = map_type(type, db_type, **options)
|
47
49
|
end
|
48
50
|
|
49
51
|
type.meta(primary_key: true)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'sequel/core'
|
2
4
|
|
3
|
-
Sequel.extension(
|
5
|
+
Sequel.extension(:pg_array, :pg_array_ops)
|
4
6
|
|
5
7
|
require 'rom/sql/extensions/postgres/types/array_types'
|
6
8
|
|
@@ -120,7 +122,7 @@ module ROM
|
|
120
122
|
Attribute[type].meta(sql_expr: expr.pg_array[idx])
|
121
123
|
end
|
122
124
|
|
123
|
-
def any(
|
125
|
+
def any(_type, expr, value)
|
124
126
|
Attribute[SQL::Types::Bool].meta(sql_expr: { value => expr.pg_array.any })
|
125
127
|
end
|
126
128
|
|
@@ -128,7 +130,7 @@ module ROM
|
|
128
130
|
Attribute[SQL::Types::Bool].meta(sql_expr: expr.pg_array.contained_by(type[other]))
|
129
131
|
end
|
130
132
|
|
131
|
-
def length(
|
133
|
+
def length(_type, expr)
|
132
134
|
Attribute[SQL::Types::Integer].meta(sql_expr: expr.pg_array.length)
|
133
135
|
end
|
134
136
|
|
@@ -140,7 +142,7 @@ module ROM
|
|
140
142
|
Attribute[type].meta(sql_expr: expr.pg_array.remove(cast(type, value)))
|
141
143
|
end
|
142
144
|
|
143
|
-
def join(
|
145
|
+
def join(_type, expr, delimiter = '', null = nil)
|
144
146
|
Attribute[SQL::Types::String].meta(sql_expr: expr.pg_array.join(delimiter, null))
|
145
147
|
end
|
146
148
|
|
@@ -151,8 +153,7 @@ module ROM
|
|
151
153
|
private
|
152
154
|
|
153
155
|
def cast(type, value)
|
154
|
-
|
155
|
-
Sequel.cast(value, db_type)
|
156
|
+
Sequel.cast(value, type.meta[:type])
|
156
157
|
end
|
157
158
|
end
|
158
159
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rom/sql/type_extensions'
|
2
4
|
|
3
5
|
module ROM
|
@@ -52,7 +54,7 @@ module ROM
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
|
-
def build_read_type(
|
57
|
+
def build_read_type(_db_type, member_type)
|
56
58
|
if member_type && member_type.meta[:read]
|
57
59
|
base_read_type.of(member_type.meta[:read])
|
58
60
|
else
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'sequel/core'
|
4
|
+
require 'singleton'
|
2
5
|
|
3
|
-
Sequel.extension(
|
6
|
+
Sequel.extension(:pg_json, :pg_json_ops)
|
4
7
|
|
5
8
|
module ROM
|
6
9
|
module SQL
|
@@ -16,16 +19,70 @@ module ROM
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
class JSONNullType
|
23
|
+
include ::Singleton
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
'null'
|
27
|
+
end
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
'null'
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
34
|
+
JSONNull = JSONNullType.instance.freeze
|
35
|
+
|
36
|
+
if ::Sequel.respond_to?(:pg_json_wrap)
|
37
|
+
primitive_json_types = [
|
38
|
+
SQL::Types::Array,
|
39
|
+
SQL::Types::Hash,
|
40
|
+
SQL::Types::Integer,
|
41
|
+
SQL::Types::Float,
|
42
|
+
SQL::Types::String,
|
43
|
+
SQL::Types::True,
|
44
|
+
SQL::Types::False
|
45
|
+
]
|
46
|
+
|
47
|
+
JSON = Type('json') do
|
48
|
+
casts = ::Hash.new(-> v { ::Sequel.pg_json(v) })
|
49
|
+
json_null = ::Sequel.pg_json_wrap(nil)
|
50
|
+
casts[JSONNullType] = -> _ { json_null }
|
51
|
+
casts[::NilClass] = -> _ { json_null }
|
52
|
+
primitive_json_types.each do |type|
|
53
|
+
casts[type.primitive] = -> v { ::Sequel.pg_json_wrap(v) }
|
54
|
+
end
|
55
|
+
casts.freeze
|
56
|
+
|
57
|
+
[*primitive_json_types, SQL::Types.Constant(JSONNull)]
|
58
|
+
.reduce(:|)
|
59
|
+
.constructor { |value| casts[value.class].(value) }
|
60
|
+
.meta(read: JSONRead)
|
61
|
+
end
|
62
|
+
|
63
|
+
JSONB = Type('jsonb') do
|
64
|
+
casts = ::Hash.new(-> v { ::Sequel.pg_jsonb(v) })
|
65
|
+
jsonb_null = ::Sequel.pg_jsonb_wrap(nil)
|
66
|
+
casts[JSONNullType] = -> _ { jsonb_null }
|
67
|
+
casts[::NilClass] = -> _ { jsonb_null }
|
68
|
+
primitive_json_types.each do |type|
|
69
|
+
casts[type.primitive] = -> v { ::Sequel.pg_jsonb_wrap(v) }
|
70
|
+
end
|
71
|
+
casts.freeze
|
72
|
+
|
73
|
+
[*primitive_json_types, SQL::Types.Constant(JSONNull)]
|
74
|
+
.reduce(:|)
|
75
|
+
.constructor { |value| casts[value.class].(value) }
|
76
|
+
.meta(read: JSONRead)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
JSON = Type('json') do
|
80
|
+
(SQL::Types::Array | SQL::Types::Hash).constructor(Sequel.method(:pg_json)).meta(read: JSONRead)
|
81
|
+
end
|
82
|
+
|
83
|
+
JSONB = Type('jsonb') do
|
84
|
+
(SQL::Types::Array | SQL::Types::Hash).constructor(Sequel.method(:pg_jsonb)).meta(read: JSONRead)
|
85
|
+
end
|
29
86
|
end
|
30
87
|
|
31
88
|
# @!parse
|
@@ -173,11 +230,11 @@ module ROM
|
|
173
230
|
end
|
174
231
|
end
|
175
232
|
|
176
|
-
def get(
|
233
|
+
def get(_type, expr, *path)
|
177
234
|
Attribute[json_type].meta(sql_expr: wrap(expr)[path_args(path)])
|
178
235
|
end
|
179
236
|
|
180
|
-
def get_text(
|
237
|
+
def get_text(_type, expr, *path)
|
181
238
|
Attribute[SQL::Types::String].meta(sql_expr: wrap(expr).get_text(path_args(path)))
|
182
239
|
end
|
183
240
|
|
@@ -185,7 +242,7 @@ module ROM
|
|
185
242
|
|
186
243
|
def path_args(path)
|
187
244
|
case path.size
|
188
|
-
when 0 then raise ArgumentError,
|
245
|
+
when 0 then raise ArgumentError, 'wrong number of arguments (given 0, expected 1+)'
|
189
246
|
when 1 then path[0]
|
190
247
|
else path
|
191
248
|
end
|
@@ -199,32 +256,32 @@ module ROM
|
|
199
256
|
TypeExtensions.register(JSONB) do
|
200
257
|
include JSONMethods[JSONB, :pg_jsonb.to_proc]
|
201
258
|
|
202
|
-
def contain(
|
259
|
+
def contain(_type, expr, value)
|
203
260
|
Attribute[SQL::Types::Bool].meta(sql_expr: wrap(expr).contains(value))
|
204
261
|
end
|
205
262
|
|
206
|
-
def contained_by(
|
263
|
+
def contained_by(_type, expr, value)
|
207
264
|
Attribute[SQL::Types::Bool].meta(sql_expr: wrap(expr).contained_by(value))
|
208
265
|
end
|
209
266
|
|
210
|
-
def has_key(
|
267
|
+
def has_key(_type, expr, key)
|
211
268
|
Attribute[SQL::Types::Bool].meta(sql_expr: wrap(expr).has_key?(key))
|
212
269
|
end
|
213
270
|
|
214
|
-
def has_any_key(
|
271
|
+
def has_any_key(_type, expr, *keys)
|
215
272
|
Attribute[SQL::Types::Bool].meta(sql_expr: wrap(expr).contain_any(keys))
|
216
273
|
end
|
217
274
|
|
218
|
-
def has_all_keys(
|
275
|
+
def has_all_keys(_type, expr, *keys)
|
219
276
|
Attribute[SQL::Types::Bool].meta(sql_expr: wrap(expr).contain_all(keys))
|
220
277
|
end
|
221
278
|
|
222
|
-
def merge(
|
279
|
+
def merge(_type, expr, value)
|
223
280
|
Attribute[JSONB].meta(sql_expr: wrap(expr).concat(value))
|
224
281
|
end
|
225
282
|
alias_method :+, :merge
|
226
283
|
|
227
|
-
def delete(
|
284
|
+
def delete(_type, expr, *path)
|
228
285
|
sql_expr = path.size == 1 ? wrap(expr) - path : wrap(expr).delete_path(path)
|
229
286
|
Attribute[JSONB].meta(sql_expr: sql_expr)
|
230
287
|
end
|