opium 1.1.8 → 1.2.0
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/CHANGELOG.md +4 -0
- data/lib/opium/extensions/pointer.rb +1 -0
- data/lib/opium/model.rb +2 -0
- data/lib/opium/model/attributable.rb +6 -2
- data/lib/opium/model/batchable.rb +83 -0
- data/lib/opium/model/batchable/batch.rb +1 -2
- data/lib/opium/model/connectable.rb +1 -1
- data/lib/opium/model/criteria.rb +4 -4
- data/lib/opium/model/field.rb +12 -2
- data/lib/opium/model/fieldable.rb +12 -2
- data/lib/opium/model/persistable.rb +1 -1
- data/lib/opium/model/reference.rb +50 -0
- data/lib/opium/model/relatable.rb +64 -0
- data/lib/opium/model/relatable/metadata.rb +32 -0
- data/lib/opium/model/relation.rb +156 -0
- data/lib/opium/version.rb +1 -1
- data/spec/opium/model/attributable_spec.rb +0 -9
- data/spec/opium/model/batchable/batch_spec.rb +4 -1
- data/spec/opium/model/batchable_spec.rb +148 -0
- data/spec/opium/model/fieldable_spec.rb +16 -0
- data/spec/opium/model/reference_spec.rb +73 -0
- data/spec/opium/model/relatable/metadata_spec.rb +31 -0
- data/spec/opium/model/relatable_spec.rb +220 -0
- data/spec/opium/model/relation_spec.rb +275 -0
- data/spec/opium/model_spec.rb +1 -0
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bbf318b07ca2a59bb917e4495abda45117aa588
|
4
|
+
data.tar.gz: c85609101238b4c6142df1d421a90e33e9fbf38a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 661189662f2ac5cdeb1b0dcb87d32ca291bdb4e888a108e7669153758160ced3f4aa06e961e625544e87c4e7d66a514e588607f0338f81793ee7029ee5266093
|
7
|
+
data.tar.gz: 76ef297dfd71c71a063140c88f11b48bfb6326b6ca31d333155ac9d6cdbb0917c181d337a7e67adb2038af6261cf4387644ed98211208e932d2e25d9346a3b47
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,7 @@ module Opium
|
|
2
2
|
class Pointer
|
3
3
|
def initialize( attributes = {} )
|
4
4
|
self.class_name = attributes[:class_name] || attributes[:model_name] || (attributes[:class] || attributes[:model]).model_name
|
5
|
+
self.class_name = self.class_name.name if self.class_name.respond_to?(:name)
|
5
6
|
self.id = attributes[:id]
|
6
7
|
end
|
7
8
|
|
data/lib/opium/model.rb
CHANGED
@@ -17,6 +17,7 @@ require 'opium/model/scopable'
|
|
17
17
|
require 'opium/model/findable'
|
18
18
|
require 'opium/model/inheritable'
|
19
19
|
require 'opium/model/batchable'
|
20
|
+
require 'opium/model/relatable'
|
20
21
|
require 'opium/model/kaminari'
|
21
22
|
|
22
23
|
module Opium
|
@@ -38,6 +39,7 @@ module Opium
|
|
38
39
|
include Findable
|
39
40
|
include Inheritable
|
40
41
|
include Batchable
|
42
|
+
include Relatable
|
41
43
|
end
|
42
44
|
|
43
45
|
def initialize( attributes = {} )
|
@@ -7,8 +7,12 @@ module Opium
|
|
7
7
|
include ActiveModel::ForbiddenAttributesProtection
|
8
8
|
end
|
9
9
|
|
10
|
+
def initialize( attributes = {} )
|
11
|
+
super( self.class.default_attributes( self ).merge attributes )
|
12
|
+
end
|
13
|
+
|
10
14
|
def attributes
|
11
|
-
@attributes ||=
|
15
|
+
@attributes ||= {}.with_indifferent_access
|
12
16
|
end
|
13
17
|
|
14
18
|
def attributes=(values)
|
@@ -23,7 +27,7 @@ module Opium
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def attributes_to_parse( options = {} )
|
26
|
-
options[:except] ||= self.class.fields.values.select {|f| f.readonly? }.map {|f| f.name} if options[:not_readonly]
|
30
|
+
options[:except] ||= self.class.fields.values.select {|f| f.readonly? || f.virtual? }.map {|f| f.name} if options[:not_readonly]
|
27
31
|
Hash[*self.as_json( options ).flat_map {|k, v| [self.class.fields[k].name_to_parse, self.class.fields[k].type.to_parse(v)]}]
|
28
32
|
end
|
29
33
|
|
@@ -5,6 +5,89 @@ module Opium
|
|
5
5
|
module Model
|
6
6
|
module Batchable
|
7
7
|
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
require 'fiber'
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def batch( options = {} )
|
13
|
+
raise ArgumentError, 'no block given' unless block_given?
|
14
|
+
create_batch
|
15
|
+
fiber = Fiber.new { yield }
|
16
|
+
subfibers = []
|
17
|
+
subfibers << fiber.resume while fiber.alive?
|
18
|
+
ensure
|
19
|
+
delete_batch
|
20
|
+
end
|
21
|
+
|
22
|
+
def batched?
|
23
|
+
batch_pool[Thread.current].present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_batch
|
27
|
+
batch = current_batch_job
|
28
|
+
if batch
|
29
|
+
batch.dive && batch
|
30
|
+
else
|
31
|
+
self.current_batch_job = Batch.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete_batch
|
36
|
+
batch = current_batch_job
|
37
|
+
fail 'No current batch job!' unless batch
|
38
|
+
if batch.depth == 0
|
39
|
+
self.current_batch_job = nil
|
40
|
+
else
|
41
|
+
batch.execute
|
42
|
+
batch
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def current_batch_job
|
47
|
+
batch_pool[Thread.current]
|
48
|
+
end
|
49
|
+
|
50
|
+
def current_batch_job=( value )
|
51
|
+
batch_pool[Thread.current] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
def http_post( data, options = {} )
|
55
|
+
if batched?
|
56
|
+
current_batch_job.enqueue( method: :post, path: resource_name, body: data )
|
57
|
+
Fiber.yield
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def http_put( id, data, options = {} )
|
64
|
+
if batched?
|
65
|
+
current_batch_job.enqueue( method: :put, path: resource_name( id ), body: data )
|
66
|
+
Fiber.yield
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def http_delete( id, options = {} )
|
73
|
+
if batched?
|
74
|
+
current_batch_job.enqueue( method: :delete, path: resource_name( id ) )
|
75
|
+
Fiber.yield
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def batch_pool
|
84
|
+
@batch_pool ||= {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def thread_local_id
|
88
|
+
@thread_local_id ||= :"#{ Module.nesting.first.name.parameterize('_') }_current_batch_job"
|
89
|
+
end
|
90
|
+
end
|
8
91
|
end
|
9
92
|
end
|
10
93
|
end
|
@@ -23,6 +23,7 @@ module Opium
|
|
23
23
|
@@connection ||= Faraday.new( url: 'https://api.parse.com/1/' ) do |faraday|
|
24
24
|
faraday.request :multipart
|
25
25
|
faraday.request :url_encoded
|
26
|
+
faraday.request :json
|
26
27
|
faraday.response :logger if Opium.config.log_network_responses
|
27
28
|
faraday.response :json, content_type: /\bjson$/
|
28
29
|
faraday.headers[:x_parse_application_id] = Opium.config.app_id
|
@@ -125,7 +126,6 @@ module Opium
|
|
125
126
|
def infuse_request_with( data )
|
126
127
|
lambda do |request|
|
127
128
|
request.body = data
|
128
|
-
request.body = request.body.to_json unless request.body.is_a?(String)
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
data/lib/opium/model/criteria.rb
CHANGED
@@ -23,7 +23,7 @@ module Opium
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def chain
|
26
|
-
Marshal.load( Marshal.dump( self ) )
|
26
|
+
Marshal.load( Marshal.dump( self ) ).tap {|m| m.instance_variable_set( :@cache, nil )}
|
27
27
|
end
|
28
28
|
|
29
29
|
def constraints
|
@@ -81,9 +81,9 @@ module Opium
|
|
81
81
|
if response && response['results']
|
82
82
|
variables[:total_count] = response['count']
|
83
83
|
response['results'].each do |attributes|
|
84
|
-
|
85
|
-
@cache <<
|
86
|
-
block.call
|
84
|
+
instance = self.model.new( attributes )
|
85
|
+
@cache << instance if cached?
|
86
|
+
block.call instance
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
data/lib/opium/model/field.rb
CHANGED
@@ -7,9 +7,11 @@ module Opium
|
|
7
7
|
|
8
8
|
attr_reader :name, :type, :readonly, :as
|
9
9
|
|
10
|
-
def default
|
10
|
+
def default( context = nil )
|
11
11
|
if @default.respond_to? :call
|
12
|
-
|
12
|
+
params = []
|
13
|
+
params.push( context ) if @default.arity != 0
|
14
|
+
@default.call( *params )
|
13
15
|
else
|
14
16
|
@default
|
15
17
|
end
|
@@ -19,6 +21,14 @@ module Opium
|
|
19
21
|
self.readonly == true
|
20
22
|
end
|
21
23
|
|
24
|
+
def relation?
|
25
|
+
self.type == Relation
|
26
|
+
end
|
27
|
+
|
28
|
+
def virtual?
|
29
|
+
relation? || self.type == Reference
|
30
|
+
end
|
31
|
+
|
22
32
|
def name_to_parse
|
23
33
|
@name_to_parse ||= (self.as || self.name).to_s.camelize(:lower)
|
24
34
|
end
|
@@ -28,6 +28,10 @@ module Opium
|
|
28
28
|
define_method("#{name}=") do |value|
|
29
29
|
converted = self.class.fields[name].type.to_ruby(value)
|
30
30
|
send( "#{name}_will_change!" ) unless self.attributes[name] == converted
|
31
|
+
if self.class.fields[name].relation?
|
32
|
+
converted.owner ||= self
|
33
|
+
converted.metadata ||= self.class.relations[name]
|
34
|
+
end
|
31
35
|
self.attributes[name] = converted
|
32
36
|
end
|
33
37
|
send(:private, "#{name}=") if options[:readonly]
|
@@ -36,6 +40,12 @@ module Opium
|
|
36
40
|
fields[name]
|
37
41
|
end
|
38
42
|
|
43
|
+
def has_field?( field_name )
|
44
|
+
fields.key? field_name
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :field?, :has_field?
|
48
|
+
|
39
49
|
def fields
|
40
50
|
@fields ||= ActiveSupport::HashWithIndifferentAccess.new
|
41
51
|
end
|
@@ -48,8 +58,8 @@ module Opium
|
|
48
58
|
@parse_canonical_field_names ||= ActiveSupport::HashWithIndifferentAccess.new
|
49
59
|
end
|
50
60
|
|
51
|
-
def default_attributes
|
52
|
-
fields.transform_values {|field| field.type.to_ruby field.default}.with_indifferent_access
|
61
|
+
def default_attributes( context = nil )
|
62
|
+
fields.transform_values {|field| field.type.to_ruby field.default( context ) }.with_indifferent_access
|
53
63
|
end
|
54
64
|
end
|
55
65
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Opium
|
2
|
+
module Model
|
3
|
+
class Reference < SimpleDelegator
|
4
|
+
class << self
|
5
|
+
def to_ruby( value )
|
6
|
+
case value
|
7
|
+
when Hash
|
8
|
+
new( value[:metadata] || value['metadata'], value[:context] || value['context'] )
|
9
|
+
when self
|
10
|
+
value
|
11
|
+
else
|
12
|
+
fail ArgumentError, "could not convert #{ value.inspect } into an Opium::Model::Reference"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize( metadata, context )
|
18
|
+
self.metadata = metadata
|
19
|
+
self.context = context
|
20
|
+
fail ArgumentError, 'did not receive a context object!' unless context
|
21
|
+
super( nil )
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_accessor :metadata, :context
|
25
|
+
|
26
|
+
def __getobj__
|
27
|
+
@reference || __setobj__( lookup_reference )
|
28
|
+
end
|
29
|
+
|
30
|
+
def __setobj__( obj )
|
31
|
+
@reference = obj
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
if @reference
|
36
|
+
@reference.inspect
|
37
|
+
else
|
38
|
+
"#<#{ self.class.name }<#{ self.metadata.target_class_name }>>"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def lookup_reference
|
45
|
+
return nil if context.new_record?
|
46
|
+
self.metadata.target_class_name.constantize.where( self.metadata.inverse_relation_name => self.context ).first
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'opium/model/relation'
|
2
|
+
require 'opium/model/reference'
|
3
|
+
require 'opium/model/relatable/metadata'
|
4
|
+
|
5
|
+
module Opium
|
6
|
+
module Model
|
7
|
+
module Relatable
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
after_create :update_relations
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def relations
|
16
|
+
@relations ||= {}.with_indifferent_access
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_and_belongs_to_many( relation_name, options = {} )
|
20
|
+
create_relation_metadata_from( :has_and_belongs_to_many, relation_name, options )
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_many( relation_name, options = {} )
|
24
|
+
create_relation_metadata_from( :has_many, relation_name, options )
|
25
|
+
field relation_name, type: Relation, default: -> { relations[relation_name].target_class_name }
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_one( relation_name, options = {} )
|
29
|
+
create_relation_metadata_from( :has_one, relation_name, options )
|
30
|
+
end
|
31
|
+
|
32
|
+
def belongs_to( relation_name, options = {} )
|
33
|
+
create_relation_metadata_from( :belongs_to, relation_name, options )
|
34
|
+
field relation_name, type: Reference,
|
35
|
+
default: ->( model ) do
|
36
|
+
{ metadata: relations[relation_name], context: model }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def create_relation_metadata_from( relation_type, relation_name, options )
|
43
|
+
relations[relation_name] = Metadata.new( self, relation_type, relation_name, options )
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def save( options = {} )
|
48
|
+
super && relations.all? {|_, relation| relation.save}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def relations
|
54
|
+
attributes.select {|_, value| value.is_a? Relation}
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_relations
|
58
|
+
send(:relations).each do |_, value|
|
59
|
+
value.owner = self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Opium
|
2
|
+
module Model
|
3
|
+
module Relatable
|
4
|
+
class Metadata
|
5
|
+
attr_reader :relation_name, :inverse_relation_name, :target_class_name, :relation_type, :inverse_relation_type, :owning_class_name
|
6
|
+
|
7
|
+
def initialize( klass, relation_type, relation_name, options = {} )
|
8
|
+
self.owning_class_name = klass.model_name
|
9
|
+
self.relation_type = relation_type
|
10
|
+
self.relation_name = relation_name
|
11
|
+
self.target_class_name = (options[:class_name] || relation_name).to_s.classify
|
12
|
+
self.inverse_relation_name = (options[:inverse_of] || determine_inverse_relation_name).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_writer :relation_name, :inverse_relation_name, :target_class_name, :relation_type, :inverse_relation_type, :owning_class_name
|
18
|
+
|
19
|
+
def determine_inverse_relation_name
|
20
|
+
method =
|
21
|
+
case relation_type
|
22
|
+
when :belongs_to
|
23
|
+
:plural
|
24
|
+
else
|
25
|
+
:singular
|
26
|
+
end
|
27
|
+
owning_class_name.send( method )
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Opium
|
2
|
+
module Model
|
3
|
+
class Relation < Criteria
|
4
|
+
include ActiveModel::Dirty
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def to_parse( object )
|
8
|
+
class_name =
|
9
|
+
case object
|
10
|
+
when Hash
|
11
|
+
fetch_hash_key_from( object, 'class_name' ) || fetch_hash_key_from( object, 'model_name' )
|
12
|
+
when String, Symbol
|
13
|
+
object
|
14
|
+
when is_descendant.curry[Opium::Model]
|
15
|
+
object.model_name
|
16
|
+
when self
|
17
|
+
object.class_name
|
18
|
+
else
|
19
|
+
fail ArgumentError, "could not convert #{ object.inspect } to a parse Relation hash"
|
20
|
+
end
|
21
|
+
fail ArgumentError, "could not determine class_name from #{ object.inspect }" unless class_name
|
22
|
+
{ __type: 'Relation', className: class_name }.with_indifferent_access
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_ruby( object )
|
26
|
+
return if object.nil?
|
27
|
+
return object if object.is_a? self
|
28
|
+
class_name =
|
29
|
+
case object
|
30
|
+
when Hash
|
31
|
+
fetch_hash_key_from( object, 'class_name' ) || fetch_hash_key_from( object, 'model_name' )
|
32
|
+
when String, Symbol
|
33
|
+
object
|
34
|
+
when is_descendant.curry[Opium::Model]
|
35
|
+
object.model_name
|
36
|
+
else
|
37
|
+
fail ArgumentError, "could not convert #{ object.inspect } to a Opium::Model::Relation"
|
38
|
+
end
|
39
|
+
new( class_name )
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def is_descendant
|
45
|
+
@is_descendant ||= ->( expected_type, object ) { ( object.is_a?( Class ) ? object : object.class ) <= expected_type }
|
46
|
+
end
|
47
|
+
|
48
|
+
def fetch_hash_key_from( hash, key )
|
49
|
+
snake_case_key = key.to_s.underscore
|
50
|
+
lower_camel_key = key.to_s.camelcase(:lower)
|
51
|
+
|
52
|
+
hash[ snake_case_key ] || hash[ snake_case_key.to_sym ] || hash[ lower_camel_key ] || hash[ lower_camel_key.to_sym ]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize( model_name )
|
57
|
+
super
|
58
|
+
update_variable!( :cache, true )
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_parse
|
62
|
+
self.class.to_parse self
|
63
|
+
end
|
64
|
+
|
65
|
+
def empty?
|
66
|
+
owner.nil? || owner.new_record? ? true : super
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :owner, :metadata
|
70
|
+
|
71
|
+
def owner=(value)
|
72
|
+
@owner = value
|
73
|
+
update_constraint!( :where, '$relatedTo' => { 'object' => value.to_parse } )
|
74
|
+
end
|
75
|
+
|
76
|
+
def metadata=(value)
|
77
|
+
@metadata = value
|
78
|
+
update_constraint!( :where, '$relatedTo' => { 'key' => value.relation_name.to_s } )
|
79
|
+
end
|
80
|
+
|
81
|
+
alias_method :class_name, :model_name
|
82
|
+
|
83
|
+
#TODO: likely will need to reimplement .each
|
84
|
+
|
85
|
+
def each(&block)
|
86
|
+
if !block_given?
|
87
|
+
to_enum(:each)
|
88
|
+
else
|
89
|
+
super() {|model| block.call( model ) unless __deletions__.include?( model ) }
|
90
|
+
(__additions__ - __deletions__).each(&block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def push( object )
|
95
|
+
__additions__.push( object )
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
alias_method :<<, :push
|
100
|
+
|
101
|
+
def delete( object )
|
102
|
+
__deletions__.push( object )
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
def build( params = {} )
|
107
|
+
model.new( params || {} ).tap do |instance|
|
108
|
+
push instance
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
alias_method :new, :build
|
113
|
+
|
114
|
+
def save
|
115
|
+
self.reject {|model| model.persisted?}.each(&:save)
|
116
|
+
__apply_additions__
|
117
|
+
__apply_deletions__
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_response
|
122
|
+
@parse_response ||= []
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def __relation_deltas__
|
128
|
+
@__relation_deltas__ ||= {}
|
129
|
+
end
|
130
|
+
|
131
|
+
def __additions__
|
132
|
+
__relation_deltas__[:additions] ||= []
|
133
|
+
end
|
134
|
+
|
135
|
+
def __deletions__
|
136
|
+
__relation_deltas__[:deletions] ||= []
|
137
|
+
end
|
138
|
+
|
139
|
+
def __apply_additions__
|
140
|
+
unless __additions__.empty?
|
141
|
+
parse_response << owner.class.http_put( owner.id, { metadata.relation_name => { __op: 'AddRelation', objects: __additions__.map(&:to_parse) } } )
|
142
|
+
@cache.concat( __additions__ )
|
143
|
+
__additions__.clear
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def __apply_deletions__
|
148
|
+
unless __deletions__.empty?
|
149
|
+
parse_response << owner.class.http_put( owner.id, { metadata.relation_name => { __op: 'RemoveRelation', objects: __deletions__.map(&:to_parse) } } )
|
150
|
+
@cache = @cache - __deletions__
|
151
|
+
__deletions__.clear
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|