global-registry-bindings 0.0.6 → 0.1.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/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
|