global-registry-bindings 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +79 -35
- data/lib/global_registry_bindings/entity/entity_type_methods.rb +35 -33
- data/lib/global_registry_bindings/entity/mdm_methods.rb +9 -19
- data/lib/global_registry_bindings/entity/push_entity_methods.rb +31 -38
- data/lib/global_registry_bindings/entity/push_relationship_methods.rb +61 -47
- data/lib/global_registry_bindings/entity/relationship_type_methods.rb +48 -37
- data/lib/global_registry_bindings/exceptions.rb +1 -0
- data/lib/global_registry_bindings/global_registry_bindings.rb +129 -46
- data/lib/global_registry_bindings/{entity/delete_entity_methods.rb → model/delete_entity.rb} +5 -5
- data/lib/global_registry_bindings/model/entity.rb +64 -0
- data/lib/global_registry_bindings/model/pull_mdm.rb +23 -0
- data/lib/global_registry_bindings/model/push_entity.rb +21 -0
- data/lib/global_registry_bindings/model/push_relationship.rb +79 -0
- data/lib/global_registry_bindings/model/relationship.rb +68 -0
- data/lib/global_registry_bindings/options.rb +26 -59
- data/lib/global_registry_bindings/options/entity_class_options.rb +34 -0
- data/lib/global_registry_bindings/options/entity_instance_options.rb +90 -0
- data/lib/global_registry_bindings/options/entity_options_parser.rb +76 -0
- data/lib/global_registry_bindings/options/relationship_class_options.rb +37 -0
- data/lib/global_registry_bindings/options/relationship_instance_options.rb +131 -0
- data/lib/global_registry_bindings/options/relationship_options_parser.rb +98 -0
- data/lib/global_registry_bindings/railtie.rb +2 -1
- data/lib/global_registry_bindings/version.rb +1 -1
- data/lib/global_registry_bindings/worker.rb +25 -0
- data/lib/global_registry_bindings/workers/{delete_gr_entity_worker.rb → delete_entity_worker.rb} +1 -6
- data/lib/global_registry_bindings/workers/pull_mdm_id_worker.rb +12 -13
- data/lib/global_registry_bindings/workers/push_entity_worker.rb +24 -0
- data/lib/global_registry_bindings/workers/push_relationship_worker.rb +17 -7
- data/spec/acceptance/global_registry_bindings_spec.rb +50 -40
- data/spec/factories/factories.rb +24 -0
- data/spec/fixtures/get_entity_types_area.json +44 -0
- data/spec/fixtures/post_entities_community.json +8 -0
- data/spec/fixtures/post_relationship_types_fancy_org_area.json +16 -0
- data/spec/fixtures/put_entities_community_relationship.json +16 -0
- data/spec/fixtures/put_entities_fancy_org_area_relationship.json +8 -0
- data/spec/fixtures/put_entities_fancy_org_relationship.json +17 -0
- data/spec/fixtures/put_entities_person_country_relationship.json +23 -0
- data/spec/fixtures/put_entities_relationship_400.json +3 -0
- data/spec/fixtures/put_relationship_types_fields_fancy_org_area.json +25 -0
- data/spec/helpers/sidekiq_helpers.rb +14 -0
- data/spec/internal/app/models/address.rb +7 -2
- data/spec/internal/app/models/area.rb +7 -0
- data/spec/internal/app/models/assignment.rb +5 -4
- data/spec/internal/app/models/community.rb +19 -0
- data/spec/internal/app/models/country.rb +8 -0
- data/spec/internal/app/models/namespaced/person.rb +48 -2
- data/spec/internal/app/models/organization.rb +26 -3
- data/spec/internal/db/schema.rb +28 -0
- data/spec/internal/log/test.log +71023 -0
- data/spec/models/address_spec.rb +6 -204
- data/spec/models/assignment_spec.rb +40 -186
- data/spec/models/organization_spec.rb +106 -92
- data/spec/models/person_spec.rb +158 -214
- data/spec/models/user_edited_person_spec.rb +2 -2
- data/spec/spec_helper.rb +5 -6
- data/spec/workers/delete_gr_entity_worker_spec.rb +4 -4
- data/spec/workers/pull_mdm_id_worker_spec.rb +94 -32
- data/spec/workers/push_entity_worker_spec.rb +476 -0
- data/spec/workers/push_relationship_worker_spec.rb +344 -15
- metadata +45 -10
- data/lib/global_registry_bindings/entity/entity_methods.rb +0 -62
- data/lib/global_registry_bindings/options/class_options.rb +0 -62
- data/lib/global_registry_bindings/options/instance_options.rb +0 -63
- data/lib/global_registry_bindings/workers/push_gr_entity_worker.rb +0 -22
- data/spec/workers/push_gr_entity_worker_spec.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 451f38a412ca7fd1e2b05ff8e96d56deb1b672a8
|
4
|
+
data.tar.gz: 9af6074f11baf7031348356041f970dae848241f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d496aebf53060214bf787551c9b45b306ebf0a333f9840dc33383d17faa8d19345b9d5563a46f3a5af2f4831cd1ac505ab9e2ec22f9e68cc6e82b077bd09ad5
|
7
|
+
data.tar.gz: 06f34a68d132652485564106595954833b359e8c0054b679f09227aff5923ae08ffe5f3212d08863da828605bf4b9871150d76ccf625a92fef6049d5ff370580
|
data/README.md
CHANGED
@@ -49,32 +49,90 @@ end
|
|
49
49
|
|
50
50
|
You can pass various options to the `global_registry_bindings` method. Configuration options are:
|
51
51
|
|
52
|
-
* `:
|
53
|
-
(default: `:
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
* `:binding`: Type of Global Registry binding. Either `:entity` or `:relationship`.
|
53
|
+
(default: `:entity`)
|
54
|
+
|
55
|
+
* `:id_column`: Column used to track the Global Registry ID for the model instance or relationship entity.
|
56
|
+
Can be a :string or :uuid column. (default: `:global_registry_id`) **[`:entity`, `:relationship`]**
|
57
|
+
|
58
|
+
* `:type`: Global Registry entity type. Accepts a Symbol or a Proc. Symbol is the name of the entity type, Proc
|
59
|
+
is passed the model instance and must return a symbol which is the entity type. Default value is underscored
|
60
|
+
name of the model. Ex: ```type: proc { |model| model.name.to_sym }```. When used in a `:relationship`, `:type`
|
61
|
+
is a unique name to identify the relationship. **[`:entity`, `:relationship`]**
|
62
|
+
|
57
63
|
* `:push_on`: Array of Active Record lifecycle events used to push changes to Global Registry.
|
58
|
-
(default: `[:create, :update, :
|
64
|
+
(default: `[:create, :update, :destroy]`) **[`:entity`]**
|
65
|
+
|
59
66
|
* `:parent_association`: Name of the Active Record parent association. Must be defined before calling
|
60
|
-
global_registry_bindings in order to determine foreign_key
|
67
|
+
global_registry_bindings in order to determine foreign_key for use in exclude_fields. Used to create a
|
68
|
+
hierarchy or to push child entity types. (Ex: person -> address) (default: `nil`) **[`:entity`]**
|
69
|
+
|
61
70
|
* `:parent_association_class`: Class name of the parent model. Required if `:parent_association` can not be used
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
71
|
+
to determine the parent class. This can happen if parent is defined by another gem, like `ancestry`.
|
72
|
+
(default: `nil`) **[`:entity`]**
|
73
|
+
|
74
|
+
* `:primary_association`: Name of the Active Record primary association. Must be defined before calling
|
75
|
+
global_registry_bindings in order to determine foreign_key for use in exclude_fields. (default: `nil`)
|
76
|
+
**[`:relationship`]**
|
77
|
+
|
78
|
+
* `:primary_association_class`: Class name of the primary model. Required if `:primary_association` can not be
|
79
|
+
used to determine the parent class. This can happen if parent is defined by another gem, like `ancestry`.
|
80
|
+
(default: `self.class`) **[`:relationship`]**
|
81
|
+
|
82
|
+
* `:primary_association_foreign_key`: Foreign Key column for the primary association. Used if foreign_key can
|
83
|
+
not be determined from `:primary_association`. (default: `:primary_association.foreign_key`)
|
84
|
+
**[`:relationship`]**
|
85
|
+
|
86
|
+
* `:related_association`: Name of the Active Record related association. Active Record association must be
|
87
|
+
defined before calling global_registry_bindings in order to determine the foreign key.
|
88
|
+
(default: `nil`) **[`:relationship`]**
|
89
|
+
|
68
90
|
* `:related_association_class`: Class name of the related model. Required if `:related_association` can not be
|
69
|
-
|
70
|
-
|
71
|
-
* `:
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
* `:
|
76
|
-
|
91
|
+
used to determine the related class. (default: `nil`) **[`:relationship`]**
|
92
|
+
|
93
|
+
* `:related_association_foreign_key`: Foreign Key column for the related association. Used if foreign_key can
|
94
|
+
not be determined from `:primary_association`. (default: `:primary_association.foreign_key`)
|
95
|
+
**[`:relationship`]**
|
96
|
+
|
97
|
+
* `:primary_relationship_name`: Name of primary relationship role. Required if `:ensure_relationship_type` is
|
98
|
+
`true`. (default: `nil`) **[`:relationship`]**
|
99
|
+
|
100
|
+
* `:related_relationship_name`: Name of the related relationship role. Required if `:ensure_relationship_type`
|
101
|
+
is `true`. (default: `nil`) **[`:relationship`]**
|
102
|
+
|
103
|
+
* `:related_association_type`: Name of the related association entity_type. Required if unable to determined
|
104
|
+
`:type` from related. (default: `nil`) **[`:relationship`]**
|
105
|
+
|
106
|
+
* `:related_global_registry_id`: Global Registry ID of a remote related entity. Proc or Symbol. Implementation
|
107
|
+
should cache this as it may be requested multiple times. (default: `nil`) **[`:relationship`]**
|
108
|
+
|
109
|
+
* `:ensure_relationship_type`: Ensure Global Registry RelationshipType exists and is up to date.
|
110
|
+
(default: `true`) **[`:relationship`]**
|
111
|
+
|
112
|
+
* `:ensure_entity_type`: Ensure Global Registry Entity Type exists and is up to date.
|
113
|
+
(default: `true`) **[`:entity`]**
|
114
|
+
|
115
|
+
* `:client_integration_id`: Client Integration ID for relationship. Proc or Symbol.
|
116
|
+
(default: `:primary_association.id`) **[`:relationship`]**
|
117
|
+
|
118
|
+
* `:exclude_fields`: Array, Proc or Symbol. Array of Model fields (as symbols) to exclude when pushing to Global
|
119
|
+
Registry. Array Will additionally include `:mdm_id_column` and `:parent_association` foreign key when defined.
|
120
|
+
If Proc, is passed type and model instance and should return an Array of the fields to exclude. If Symbol,
|
121
|
+
this should be a method name the Model instance responds to. It is passed the type and should return an Array
|
122
|
+
of fields to exclude. When Proc or Symbol are used, you must explicitly return the standard defaults.
|
123
|
+
(default: `[:id, :created_at, :updated_at, :global_registry_id]`) **[`:entity`, `:relationship`]**
|
124
|
+
|
125
|
+
* `:extra_fields`: Additional fields to send to Global Registry. Hash, Proc or Symbol. As a Hash, names are the
|
126
|
+
keys and :type attributes are the values. Ex: `{language: :string}`. Name is a symbol and type is an
|
127
|
+
ActiveRecord column type. As a Proc, it is passed the type and model instance, and should return a Hash.
|
128
|
+
As a Symbol, the model should respond to this method, is passed the type, and should return a Hash.
|
129
|
+
**[`:entity`, `:relationship`]**
|
130
|
+
|
131
|
+
* `:mdm_id_column`: Column used to enable MDM tracking and set the name of the column. MDM is disabled when this
|
132
|
+
option is nil or empty. (default: `nil`) **[`:entity`]**
|
133
|
+
|
77
134
|
* `:mdm_timeout`: Only pull mdm information at most once every `:mdm_timeout`. (default: `1.minute`)
|
135
|
+
**[`:entity`]**
|
78
136
|
|
79
137
|
## Values for `extra_fields`
|
80
138
|
|
@@ -106,20 +164,6 @@ class Person < ActiveRecord::Base
|
|
106
164
|
end
|
107
165
|
```
|
108
166
|
|
109
|
-
## Relationships
|
110
|
-
|
111
|
-
Global Registry allows for relating two entities together (many-to-many) through a relationship. An example of this
|
112
|
-
could be a Person to Person relationship. This relationship could be described as husband/spouse, or even
|
113
|
-
leader/employee. You could also relate a Person to an Organization through an assignment. The assignment can track
|
114
|
-
specific fields about the relationship.
|
115
|
-
|
116
|
-
`global-registry-bindings` supports this through the `:parent_association` and `:related_association` options.
|
117
|
-
Relationship roles, like husband/wife, are defined through the `:parent_relationship_name` and
|
118
|
-
`:related_relationship_name` options.
|
119
|
-
|
120
|
-
More information on Global Registry relationships and relationship types can be found
|
121
|
-
[here](https://github.com/CruGlobal/global_registry_docs/wiki/About-Relationships)
|
122
|
-
|
123
167
|
## Example Models
|
124
168
|
|
125
169
|
Example models can be found in the [specs](https://github.com/CruGlobal/global-registry-bindings/tree/master/spec/internal/app/models).
|
@@ -8,46 +8,48 @@ module GlobalRegistry #:nodoc:
|
|
8
8
|
module EntityTypeMethods
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
unless entity_type
|
20
|
-
entity_type = GlobalRegistry::EntityType.post(entity_type: { name: global_registry.type,
|
21
|
-
parent_id: parent_entity_id,
|
22
|
-
field_type: 'entity' })['entity_type']
|
23
|
-
end
|
24
|
-
|
25
|
-
push_entity_type_fields(entity_type)
|
26
|
-
entity_type
|
11
|
+
def push_entity_type_to_global_registry
|
12
|
+
return unless global_registry_entity.ensure_entity_type?
|
13
|
+
parent_entity_id = parent_entity_type_id
|
14
|
+
entity_type = Rails.cache.fetch(entity_type_cache_key, expires_in: 1.hour) do
|
15
|
+
GlobalRegistry::EntityType.get('filters[name]' => global_registry_entity.type,
|
16
|
+
'filters[parent_id]' => parent_entity_id)['entity_types']&.first
|
27
17
|
end
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
.each do |name, type|
|
34
|
-
GlobalRegistry::EntityType.post(entity_type: { name: name,
|
35
|
-
parent_id: entity_type['id'],
|
36
|
-
field_type: type })
|
37
|
-
end
|
19
|
+
unless entity_type
|
20
|
+
entity_type = GlobalRegistry::EntityType.post(entity_type: { name: global_registry_entity.type,
|
21
|
+
parent_id: parent_entity_id,
|
22
|
+
field_type: 'entity' })['entity_type']
|
38
23
|
end
|
39
24
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
parent_entity_type = global_registry.parent_class.send :push_entity_type
|
44
|
-
parent_entity_type&.dig('id')
|
45
|
-
end
|
25
|
+
push_entity_type_fields_to_global_registry(entity_type)
|
26
|
+
entity_type
|
27
|
+
end
|
46
28
|
|
47
|
-
|
48
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
def push_entity_type_fields_to_global_registry(entity_type)
|
32
|
+
existing_fields = entity_type['fields']&.collect { |f| f['name'].to_sym } || []
|
33
|
+
model.entity_columns_to_push
|
34
|
+
.reject { |k, _v| existing_fields.include? k }
|
35
|
+
.each do |name, type|
|
36
|
+
GlobalRegistry::EntityType.post(entity_type: { name: name,
|
37
|
+
parent_id: entity_type['id'],
|
38
|
+
field_type: type })
|
49
39
|
end
|
50
40
|
end
|
41
|
+
|
42
|
+
def parent_entity_type_id
|
43
|
+
parent = global_registry_entity&.parent
|
44
|
+
return if parent.blank? || global_registry_entity.parent_is_self?
|
45
|
+
worker = GlobalRegistry::Bindings::Workers::PushEntityWorker.new parent
|
46
|
+
parent_entity_type = worker.send :push_entity_type_to_global_registry
|
47
|
+
parent_entity_type&.dig('id')
|
48
|
+
end
|
49
|
+
|
50
|
+
def entity_type_cache_key
|
51
|
+
"GlobalRegistry::Bindings::EntityType::#{global_registry_entity.type}"
|
52
|
+
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
@@ -1,37 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'global_registry_bindings/workers/pull_mdm_id_worker'
|
4
|
-
|
5
3
|
module GlobalRegistry #:nodoc:
|
6
4
|
module Bindings #:nodoc:
|
7
5
|
module Entity #:nodoc:
|
8
6
|
module MdmMethods
|
9
7
|
extend ActiveSupport::Concern
|
10
8
|
|
11
|
-
included do
|
12
|
-
GlobalRegistry::Bindings::Workers.mdm_worker_class(self)
|
13
|
-
after_commit :pull_mdm_id_from_global_registry_async, on: %i[create update]
|
14
|
-
end
|
15
|
-
|
16
|
-
def pull_mdm_id_from_global_registry_async
|
17
|
-
"::GlobalRegistry::Bindings::Workers::#{global_registry.mdm_worker_class_name}".constantize
|
18
|
-
.perform_async(self.class, id)
|
19
|
-
end
|
20
|
-
|
21
9
|
def pull_mdm_id_from_global_registry # rubocop:disable Metrics/AbcSize
|
22
|
-
unless
|
10
|
+
unless global_registry_entity.id_value?
|
23
11
|
# Record missing Global Registry ID, enqueue it to be pushed.
|
24
|
-
push_entity_to_global_registry_async
|
12
|
+
model.push_entity_to_global_registry_async
|
25
13
|
raise GlobalRegistry::Bindings::RecordMissingGlobalRegistryId,
|
26
|
-
"#{
|
14
|
+
"#{model.class.name}(#{model.id}) has no #{global_registry_entity.id_column}; will retry"
|
27
15
|
end
|
28
|
-
entity = GlobalRegistry::Entity.find(
|
29
|
-
mdm_entity_id = dig_global_registry_mdm_id_from_entity(entity,
|
16
|
+
entity = GlobalRegistry::Entity.find(global_registry_entity.id_value, 'filters[owned_by]' => 'mdm')
|
17
|
+
mdm_entity_id = dig_global_registry_mdm_id_from_entity(entity, global_registry_entity.type.to_s)
|
30
18
|
unless mdm_entity_id
|
31
19
|
raise GlobalRegistry::Bindings::EntityMissingMdmId,
|
32
|
-
"GR entity #{
|
20
|
+
"GR entity #{global_registry_entity.id_value} for #{model.class.name}(#{model.id}) has no mdm id; " \
|
21
|
+
'will retry'
|
33
22
|
end
|
34
|
-
|
23
|
+
# rubocop:disable Rails/SkipsModelValidations
|
24
|
+
model.update_column(global_registry_entity.mdm_id_column, mdm_entity_id)
|
35
25
|
end
|
36
26
|
|
37
27
|
def dig_global_registry_mdm_id_from_entity(entity, type)
|
@@ -1,82 +1,75 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'global_registry_bindings/workers/push_gr_entity_worker'
|
4
|
-
|
5
3
|
module GlobalRegistry #:nodoc:
|
6
4
|
module Bindings #:nodoc:
|
7
5
|
module Entity #:nodoc:
|
8
6
|
module PushEntityMethods
|
9
7
|
extend ActiveSupport::Concern
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def push_entity_to_global_registry_async
|
16
|
-
::GlobalRegistry::Bindings::Workers::PushGrEntityWorker.perform_async(self.class, id)
|
17
|
-
end
|
18
|
-
|
19
|
-
def push_entity_to_global_registry
|
20
|
-
self.class.push_entity_type
|
9
|
+
def push_entity_to_global_registry # rubocop:disable Metrics/PerceivedComplexity
|
10
|
+
return if global_registry_entity.parent_required? && global_registry_entity.parent.blank?
|
11
|
+
push_entity_type_to_global_registry
|
21
12
|
|
22
|
-
if
|
13
|
+
if global_registry_entity.parent_type.present? && !global_registry_entity.parent_is_self?
|
23
14
|
create_dependent_entity_in_global_registry
|
24
|
-
elsif
|
15
|
+
elsif global_registry_entity.id_value?
|
25
16
|
update_entity_in_global_registry
|
26
17
|
else
|
27
18
|
create_entity_in_global_registry
|
28
19
|
end
|
29
20
|
rescue RestClient::ResourceNotFound
|
30
|
-
|
21
|
+
global_registry_entity.id_value = nil
|
31
22
|
push_entity_to_global_registry
|
32
23
|
end
|
33
24
|
|
34
25
|
def update_entity_in_global_registry
|
35
|
-
entity_attributes = {
|
36
|
-
GlobalRegistry::Entity.put(
|
26
|
+
entity_attributes = { global_registry_entity.type => model.entity_attributes_to_push }
|
27
|
+
GlobalRegistry::Entity.put(global_registry_entity.id_value, entity: entity_attributes)
|
37
28
|
end
|
38
29
|
|
39
30
|
def create_entity_in_global_registry
|
40
|
-
ensure_parent_entity_has_global_registry_id! if
|
41
|
-
entity_attributes = {
|
31
|
+
ensure_parent_entity_has_global_registry_id! if global_registry_entity.parent.present?
|
32
|
+
entity_attributes = { global_registry_entity.type => model.entity_attributes_to_push }
|
42
33
|
entity = GlobalRegistry::Entity.post(entity: entity_attributes)
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
global_registry_entity.id_value = dig_global_registry_id_from_entity(entity['entity'],
|
35
|
+
global_registry_entity.type)
|
36
|
+
model.update_column(global_registry_entity.id_column, # rubocop:disable Rails/SkipsModelValidations
|
37
|
+
global_registry_entity.id_value)
|
46
38
|
end
|
47
39
|
|
48
40
|
# Create or Update a child entity (ex: :email_address is a child of :person)
|
49
41
|
def create_dependent_entity_in_global_registry # rubocop:disable Metrics/AbcSize
|
50
|
-
return if
|
51
|
-
|
42
|
+
return if global_registry_entity.parent.blank?
|
43
|
+
ensure_parent_entity_has_global_registry_id!
|
52
44
|
entity_attributes = {
|
53
|
-
|
54
|
-
client_integration_id:
|
55
|
-
|
45
|
+
global_registry_entity.parent_type => {
|
46
|
+
client_integration_id: global_registry_entity.parent.id,
|
47
|
+
global_registry_entity.type => model.entity_attributes_to_push
|
56
48
|
}
|
57
49
|
}
|
58
|
-
entity = GlobalRegistry::Entity.put(
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
update_column(
|
63
|
-
|
50
|
+
entity = GlobalRegistry::Entity.put(global_registry_entity.parent_id_value, entity: entity_attributes)
|
51
|
+
global_registry_entity.id_value = dig_global_registry_id_from_entity(entity['entity'],
|
52
|
+
global_registry_entity.type,
|
53
|
+
global_registry_entity.parent_type)
|
54
|
+
model.update_column(global_registry_entity.id_column, # rubocop:disable Rails/SkipsModelValidations
|
55
|
+
global_registry_entity.id_value)
|
64
56
|
end
|
65
57
|
|
66
58
|
def dig_global_registry_id_from_entity(entity, type, parent_type = nil)
|
67
59
|
return entity&.dig(type.to_s, 'id') unless parent_type
|
68
60
|
Array.wrap(entity&.dig(parent_type.to_s, type.to_s)).detect do |item|
|
69
|
-
item['client_integration_id'] == id.to_s
|
61
|
+
item['client_integration_id'] == model.id.to_s
|
70
62
|
end&.dig('id')
|
71
63
|
end
|
72
64
|
|
73
65
|
def ensure_parent_entity_has_global_registry_id!
|
74
|
-
return unless
|
66
|
+
return unless (global_registry_entity.parent_is_self? && global_registry_entity.parent_id_value.blank?) ||
|
67
|
+
global_registry_entity.parent_id_value.blank?
|
75
68
|
# Push parent entity if it exists and is missing global_registry_id
|
76
|
-
|
69
|
+
global_registry_entity.parent.push_entity_to_global_registry_async
|
77
70
|
raise GlobalRegistry::Bindings::ParentEntityMissingGlobalRegistryId,
|
78
|
-
"#{
|
79
|
-
"#{
|
71
|
+
"#{model.class.name}(#{model.id}) has parent entity " \
|
72
|
+
"#{global_registry_entity.parent.class.name}(#{global_registry_entity.parent.id}) missing " \
|
80
73
|
'global_registry_id; will retry.'
|
81
74
|
end
|
82
75
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'global_registry'
|
4
|
-
require 'global_registry_bindings/workers/
|
4
|
+
require 'global_registry_bindings/workers/delete_entity_worker'
|
5
5
|
|
6
6
|
module GlobalRegistry #:nodoc:
|
7
7
|
module Bindings #:nodoc:
|
@@ -9,71 +9,85 @@ module GlobalRegistry #:nodoc:
|
|
9
9
|
module PushRelationshipMethods
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
|
-
included do
|
13
|
-
after_commit :push_relationship_to_global_registry_async, on: (global_registry.push_on - %i[delete])
|
14
|
-
end
|
15
|
-
|
16
|
-
def push_relationship_to_global_registry_async
|
17
|
-
::GlobalRegistry::Bindings::Workers::PushRelationshipWorker.perform_async(self.class, id)
|
18
|
-
end
|
19
|
-
|
20
12
|
def push_relationship_to_global_registry
|
21
13
|
ensure_related_entities_have_global_registry_ids!
|
22
|
-
|
23
|
-
|
24
|
-
if global_registry.id_value?
|
25
|
-
update_relationship_in_global_registry
|
26
|
-
else
|
27
|
-
create_relationship_in_global_registry
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def update_relationship_in_global_registry
|
32
|
-
GlobalRegistry::Entity.put(global_registry.id_value, entity: entity_attributes_to_push)
|
14
|
+
push_global_registry_relationship_type
|
15
|
+
create_relationship_in_global_registry
|
33
16
|
end
|
34
17
|
|
35
|
-
def create_relationship_in_global_registry
|
36
|
-
entity =
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
params: {
|
43
|
-
full_response: true,
|
44
|
-
fields: "#{global_registry.related_relationship_name}:relationship"
|
45
|
-
})
|
46
|
-
global_registry.id_value = global_registry_relationship_entity_id_from_entity entity
|
47
|
-
update_column(global_registry.id_column, # rubocop:disable Rails/SkipsModelValidations
|
48
|
-
global_registry.id_value)
|
49
|
-
# Update relationship to work around bug in Global Registry
|
50
|
-
# - If current system doesn't own a copy of the parent entity, then creating a new relationship in the same
|
51
|
-
# request will not add the relationship entity_type properties.
|
52
|
-
update_relationship_in_global_registry if global_registry.id_value?
|
18
|
+
def create_relationship_in_global_registry
|
19
|
+
entity = put_relationship_to_global_registry
|
20
|
+
global_registry_relationship(type).id_value = global_registry_relationship_entity_id_from_entity entity
|
21
|
+
model.update_column( # rubocop:disable Rails/SkipsModelValidations
|
22
|
+
global_registry_relationship(type).id_column,
|
23
|
+
global_registry_relationship(type).id_value
|
24
|
+
)
|
53
25
|
end
|
54
26
|
|
55
27
|
def global_registry_relationship_entity_id_from_entity(entity)
|
56
|
-
relationships = Array.wrap entity.dig(
|
57
|
-
|
28
|
+
relationships = Array.wrap entity.dig(
|
29
|
+
'entity',
|
30
|
+
global_registry_relationship(type).primary_type.to_s,
|
31
|
+
"#{global_registry_relationship(type).related_relationship_name}:relationship"
|
32
|
+
)
|
58
33
|
relationships.detect do |rel|
|
59
34
|
cid = rel['client_integration_id']
|
60
35
|
cid = cid['value'] if cid.is_a?(Hash)
|
61
|
-
cid ==
|
36
|
+
cid == global_registry_relationship(type).client_integration_id.to_s
|
62
37
|
end&.dig('relationship_entity_id')
|
63
38
|
end
|
64
39
|
|
65
|
-
def ensure_related_entities_have_global_registry_ids!
|
66
|
-
|
40
|
+
def ensure_related_entities_have_global_registry_ids! # rubocop:disable Metrics/AbcSize
|
41
|
+
if global_registry_relationship(type).primary_id_value.present? &&
|
42
|
+
global_registry_relationship(type).related_id_value.present?
|
43
|
+
return
|
44
|
+
end
|
67
45
|
# Enqueue push_entity worker for related entities missing global_registry_id and retry relationship push
|
68
46
|
names = []
|
69
|
-
[
|
70
|
-
next if model.
|
47
|
+
[global_registry_relationship(type).primary, global_registry_relationship(type).related].each do |model|
|
48
|
+
next if model.global_registry_entity.id_value?
|
71
49
|
names << "#{model.class.name}(#{model.id})"
|
72
50
|
model.push_entity_to_global_registry_async
|
73
51
|
end
|
74
52
|
raise GlobalRegistry::Bindings::RelatedEntityMissingGlobalRegistryId,
|
75
|
-
"#{
|
76
|
-
|
53
|
+
"#{model.class.name}(#{model.id}) has related entities [#{names.join ', '}] missing " \
|
54
|
+
'global_registry_id; will retry.'
|
55
|
+
end
|
56
|
+
|
57
|
+
def relationship_entity
|
58
|
+
{ entity: { global_registry_relationship(type).primary_type => {
|
59
|
+
"#{global_registry_relationship(type).related_relationship_name}:relationship" =>
|
60
|
+
model.relationship_attributes_to_push(type)
|
61
|
+
.merge(global_registry_relationship(type).related_type =>
|
62
|
+
global_registry_relationship(type).related_id_value)
|
63
|
+
}, client_integration_id: global_registry_relationship(type).primary.id } }
|
64
|
+
end
|
65
|
+
|
66
|
+
def put_relationship_to_global_registry
|
67
|
+
GlobalRegistry::Entity.put(
|
68
|
+
global_registry_relationship(type).primary_id_value,
|
69
|
+
relationship_entity,
|
70
|
+
params: {
|
71
|
+
full_response: true,
|
72
|
+
fields: "#{global_registry_relationship(type).related_relationship_name}:relationship"
|
73
|
+
}
|
74
|
+
)
|
75
|
+
rescue RestClient::BadRequest => e
|
76
|
+
response = JSON.parse(e.response.body)
|
77
|
+
raise unless response['error'] =~ /^Validation failed:.*already exists$/i
|
78
|
+
# Delete relationship entity and retry on 400 Bad Request (client_integration_id already exists)
|
79
|
+
delete_relationship_from_global_registry_and_retry
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete_relationship_from_global_registry_and_retry
|
83
|
+
GlobalRegistry::Bindings::Workers::DeleteEntityWorker.new.perform(global_registry_relationship(type).id_value)
|
84
|
+
model.update_column( # rubocop:disable Rails/SkipsModelValidations
|
85
|
+
global_registry_relationship(type).id_column, nil
|
86
|
+
)
|
87
|
+
raise GlobalRegistry::Bindings::RelatedEntityExistsWithCID,
|
88
|
+
"#{model.class.name}(#{model.id}) #{global_registry_relationship(type).related_relationship_name}" \
|
89
|
+
':relationship already exists with client_integration_id(' \
|
90
|
+
"#{global_registry_relationship(type).client_integration_id}). Will delete and retry."
|
77
91
|
end
|
78
92
|
end
|
79
93
|
end
|