global-registry-bindings 0.0.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +126 -0
- data/lib/global_registry_bindings.rb +8 -0
- data/lib/global_registry_bindings/entity/delete_entity_methods.rb +22 -0
- data/lib/global_registry_bindings/entity/entity_methods.rb +62 -0
- data/lib/global_registry_bindings/entity/entity_type_methods.rb +54 -0
- data/lib/global_registry_bindings/entity/mdm_methods.rb +43 -0
- data/lib/global_registry_bindings/entity/push_entity_methods.rb +78 -0
- data/lib/global_registry_bindings/entity/push_relationship_methods.rb +81 -0
- data/lib/global_registry_bindings/entity/relationship_type_methods.rb +59 -0
- data/lib/global_registry_bindings/exceptions.rb +9 -0
- data/lib/global_registry_bindings/global_registry_bindings.rb +71 -0
- data/lib/global_registry_bindings/options.rb +80 -0
- data/lib/global_registry_bindings/options/class_options.rb +58 -0
- data/lib/global_registry_bindings/options/instance_options.rb +61 -0
- data/lib/global_registry_bindings/railtie.rb +19 -0
- data/lib/global_registry_bindings/version.rb +7 -0
- data/lib/global_registry_bindings/workers/delete_gr_entity_worker.rb +22 -0
- data/lib/global_registry_bindings/workers/pull_mdm_id_worker.rb +30 -0
- data/lib/global_registry_bindings/workers/push_gr_entity_worker.rb +21 -0
- data/lib/global_registry_bindings/workers/push_relationship_worker.rb +21 -0
- data/spec/acceptance/global_registry_bindings_spec.rb +74 -0
- data/spec/factories/factories.rb +37 -0
- data/spec/fixtures/get_entities_person.json +8 -0
- data/spec/fixtures/get_entities_person_mdm.json +13 -0
- data/spec/fixtures/get_entities_person_relationship.json +32 -0
- data/spec/fixtures/get_entity_types.json +9 -0
- data/spec/fixtures/get_entity_types_address.json +59 -0
- data/spec/fixtures/get_entity_types_address_partial.json +43 -0
- data/spec/fixtures/get_entity_types_fancy_org.json +43 -0
- data/spec/fixtures/get_entity_types_fancy_org_partial.json +35 -0
- data/spec/fixtures/get_entity_types_person.json +42 -0
- data/spec/fixtures/get_entity_types_person_partial.json +34 -0
- data/spec/fixtures/get_relationship_types.json +9 -0
- data/spec/fixtures/get_relationship_types_person_fancy_org.json +41 -0
- data/spec/fixtures/get_relationship_types_person_fancy_org_partial.json +33 -0
- data/spec/fixtures/post_entities_fancy_org.json +8 -0
- data/spec/fixtures/post_entities_fancy_org_parent.json +8 -0
- data/spec/fixtures/post_entities_person.json +8 -0
- data/spec/fixtures/post_entity_types_address.json +9 -0
- data/spec/fixtures/post_entity_types_fancy_org.json +9 -0
- data/spec/fixtures/post_entity_types_person.json +9 -0
- data/spec/fixtures/post_relationship_types_person_fancy_org.json +16 -0
- data/spec/fixtures/put_entities_address.json +20 -0
- data/spec/fixtures/put_entities_person_relationship.json +29 -0
- data/spec/fixtures/put_entities_relationship.json +8 -0
- data/spec/fixtures/put_relationship_types_fields.json +33 -0
- data/spec/internal/app/models/address.rb +11 -0
- data/spec/internal/app/models/application_record.rb +5 -0
- data/spec/internal/app/models/assignment.rb +10 -0
- data/spec/internal/app/models/default.rb +6 -0
- data/spec/internal/app/models/namespaced/person.rb +18 -0
- data/spec/internal/app/models/organization.rb +12 -0
- data/spec/internal/config/database.yml +4 -0
- data/spec/internal/config/initializers/global_registry.rb +8 -0
- data/spec/internal/config/routes.rb +5 -0
- data/spec/internal/db/schema.rb +41 -0
- data/spec/internal/log/test.log +35717 -0
- data/spec/models/address_spec.rb +228 -0
- data/spec/models/assignment_spec.rb +200 -0
- data/spec/models/organization_spec.rb +127 -0
- data/spec/models/person_spec.rb +247 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/workers/delete_gr_entity_worker_spec.rb +33 -0
- data/spec/workers/pull_mdm_id_worker_spec.rb +71 -0
- data/spec/workers/push_gr_entity_worker_spec.rb +27 -0
- data/spec/workers/push_relationship_worker_spec.rb +27 -0
- metadata +458 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 70066ac805a72a8e4cd636ef0ae96c987d68900f
|
4
|
+
data.tar.gz: 1e2db15b8712f76b2cc51cfe1dfca72725b6ac2a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cf361f3f9f6a0d0d9f33c3f1ac287a7eeae6f5750d90a5d1d8308f9ca807dbc82568e1bb22afa946b9367a39fc39386435a65ee53bc2ddbccdaba6203e234f34
|
7
|
+
data.tar.gz: b121644f0d8fc5c50a10e803a9c3941349813e76926f42ebe92dc8316112f569713f444923dec4d0c1919f8ba0d956922140b6d60480e84f8e4c13c11f4fd2e1
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2017 Cru
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# Global Registry Bindings
|
2
|
+
|
3
|
+
Global Registry Bindings are a set of bindings to push ActiveRecord models to the Global Registry.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add to your Gemfile:
|
9
|
+
```ruby
|
10
|
+
gem 'global-registry-bindings'
|
11
|
+
```
|
12
|
+
|
13
|
+
Add a Global Registry initializer.
|
14
|
+
`config/initializers/global_registry.rb`
|
15
|
+
```ruby
|
16
|
+
require 'global_registry'
|
17
|
+
GlobalRegistry.configure do |config|
|
18
|
+
config.access_token = ENV['GLOBAL_REGISTRY_TOKEN'] || 'fake'
|
19
|
+
config.base_url = ENV['GLOBAL_REGISTRY_URL'] || 'https://backend.global-registry.org'
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
Make sure sidekiq is configured. See [Using Redis](https://github.com/mperham/sidekiq/wiki/Using-Redis) for information.
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
To make use of `global-registry-bindings` your model will need a few additional columns.
|
28
|
+
To push models to Global Registry, you will need a `global_registry_id` column. You additionally need a
|
29
|
+
`global_registry_mdm_id` to pull a Global Registry MDM (master data model) id. These columns should be of type
|
30
|
+
`:string` or `:uuid` and allow null values. Column names are customizable through options.
|
31
|
+
```ruby
|
32
|
+
class CreatePeople < ActiveRecord::Migration
|
33
|
+
def self.up
|
34
|
+
create_table :people do |t|
|
35
|
+
t.string :name
|
36
|
+
t.string :global_registry_id, :null => true, :index => true
|
37
|
+
t.string :global_registry_mdm_id, :null => true, :index => true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.down
|
42
|
+
drop_table :people
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
Enable `global-registry-bindings` functionality by declaring `global_registry_bindings` on your model.
|
48
|
+
```ruby
|
49
|
+
class Person < ActiveRecord::Base
|
50
|
+
global_registry_bindings mdm_id_column: :global_registry_mdm_id
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
## Options
|
55
|
+
|
56
|
+
You can pass various options to the `global_registry_bindings` method. Configuration options are:
|
57
|
+
|
58
|
+
* `:id_column`: Column used to track the Global Registry ID for the model instance. Can be a :string or :uuid column.
|
59
|
+
(default: `:global_registry_id`)
|
60
|
+
* `:mdm_id_column`: Column used to enable MDM tracking and set the name of the column. MDM is disabled when this
|
61
|
+
option is nil or empty. (default: `nil`)
|
62
|
+
* `:type`: Global Registry entity type. Default value is underscored name of the model.
|
63
|
+
* `:push_on`: Array of Active Record lifecycle events used to push changes to Global Registry.
|
64
|
+
(default: `[:create, :update, :delete]`)
|
65
|
+
* `:parent_association`: Name of the Active Record parent association. Must be defined before calling
|
66
|
+
global_registry_bindings in order to determine foreign_key field. (default: `nil`)
|
67
|
+
* `:related_association`: Name of the Active Record related association. Setting this option changes the
|
68
|
+
global registry binding from entity to relationship. Active Record association must be defined before calling
|
69
|
+
global_registry_bindings in order to determine the foreign key. `:parent_relationship_name` and
|
70
|
+
`:related_relationship_name` must be set for relationship binding to work. (default: `nil`)
|
71
|
+
* `:parent_relationship_name`: Name of parent relationship role. (default: `nil`)
|
72
|
+
* `:related_relationship_name`: Name of the related relationship role. (default: `nil`)
|
73
|
+
* `:exclude_fields`: Model fields to exclude when pushing to Global Registry. Will additionally include `:mdm_id_column`
|
74
|
+
and `:parent_association` foreign key when defined.
|
75
|
+
(default: `[:id, :created_at, :updated_at, :global_registry_id]`)
|
76
|
+
* `:extra_fields`: Additional fields to send to Global Registry. This should be a hash with name as the key
|
77
|
+
and :type attributes as the value. Ex: `{language: :string}`. Name is a symbol and type is an ActiveRecord column type.
|
78
|
+
* `:mdm_timeout`: Only pull mdm information at most once every `:mdm_timeout`. (default: `1.minute`)
|
79
|
+
|
80
|
+
## Values for `extra_fields`
|
81
|
+
|
82
|
+
Values sent to Global Registry are calculated by sending the field `name` to the model. They can be overidden by
|
83
|
+
aliasing an existing method, adding a new method to the model or by overriding the `entity_attributes_to_push`
|
84
|
+
method. If a model does not respond to a name or raises a `NoMethodError`, the field will be omitted from the request.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class Person < ActiveRecord::Base
|
88
|
+
# Person has first_name, last_name and guid columns
|
89
|
+
global_registry_bindings extra_fields: {full_name: :string, identity: :uuid, blargh: :integer},
|
90
|
+
exclude_fields: %i[guid]
|
91
|
+
|
92
|
+
# Person doesn't respond to 'blargh' so it is omitted from the attributes to push
|
93
|
+
|
94
|
+
alias_attribute :identity, :guid # Value for identity is aliased to guid
|
95
|
+
|
96
|
+
# Value for full_name
|
97
|
+
def full_name
|
98
|
+
"#{first_name} #{last_name}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Override entity_attributes_to_push to add or modify fields and values
|
102
|
+
def entity_attributes_to_push
|
103
|
+
entity_attributes = super
|
104
|
+
entity_attributes[:authentication] = { guid: guid }
|
105
|
+
entity_attributes
|
106
|
+
end
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
## Relationships
|
111
|
+
|
112
|
+
Global Registry allows for relating two entities together (many-to-many) through a relationship. An example of this
|
113
|
+
could be a Person to Person relationship. This relationship could be described as husband/spouse, or even
|
114
|
+
leader/employee. You could also relate a Person to an Organization through an assignment. The assignment can track
|
115
|
+
specific fields about the relationship.
|
116
|
+
|
117
|
+
`global-registry-bindings` supports this through the `:parent_association` and `:related_association` options.
|
118
|
+
Relationship roles, like husband/wife, are defined through the `:parent_relationship_name` and
|
119
|
+
`:related_relationship_name` options.
|
120
|
+
|
121
|
+
More information on Global Registry relationships and relationship types can be found
|
122
|
+
[here](https://github.com/CruGlobal/global_registry_docs/wiki/About-Relationships)
|
123
|
+
|
124
|
+
## Example Models
|
125
|
+
|
126
|
+
Example models can be found in the [specs](https://github.com/CruGlobal/global-registry-bindings/tree/master/spec/internal/app/models).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'global_registry_bindings/workers/delete_gr_entity_worker'
|
4
|
+
|
5
|
+
module GlobalRegistry #:nodoc:
|
6
|
+
module Bindings #:nodoc:
|
7
|
+
module Entity #:nodoc:
|
8
|
+
module DeleteEntityMethods
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
after_commit :delete_entity_from_global_registry_async, on: :destroy
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete_entity_from_global_registry_async
|
16
|
+
return unless global_registry.id_value?
|
17
|
+
::GlobalRegistry::Bindings::Workers::DeleteGrEntityWorker.perform_async(global_registry.id_value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'global_registry'
|
4
|
+
|
5
|
+
module GlobalRegistry #:nodoc:
|
6
|
+
module Bindings #:nodoc:
|
7
|
+
module Entity #:nodoc:
|
8
|
+
module EntityMethods
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
def entity_attributes_to_push
|
12
|
+
entity_attributes = self.class.columns_to_push.map do |name, type|
|
13
|
+
value_for_global_registry(name, type)
|
14
|
+
end.compact.to_h
|
15
|
+
entity_attributes[:client_integration_id] = id unless global_registry.exclude_fields
|
16
|
+
.include?(:client_integration_id)
|
17
|
+
entity_attributes[:client_updated_at] = updated_at.to_s(:db) if respond_to?(:updated_at)
|
18
|
+
entity_attributes[:parent_id] = global_registry.parent_id_value if global_registry.parent_is_self?
|
19
|
+
entity_attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
def value_for_global_registry(name, type)
|
23
|
+
value = send(name)
|
24
|
+
return [name, value] if value.nil?
|
25
|
+
value = case type
|
26
|
+
when :datetime, :date
|
27
|
+
value.to_s(:db)
|
28
|
+
when :boolean
|
29
|
+
value ? 'true' : 'false'
|
30
|
+
else
|
31
|
+
value.to_s.strip
|
32
|
+
end
|
33
|
+
[name, value]
|
34
|
+
rescue NoMethodError
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
def columns_to_push
|
40
|
+
@columns_to_push ||= columns
|
41
|
+
.collect { |c| { c.name.underscore.to_sym => normalize_column_type(c.type, c.name) } }
|
42
|
+
.reduce(&:merge)
|
43
|
+
.reject { |k, _v| global_registry.exclude_fields.include? k }
|
44
|
+
.merge(global_registry.extra_fields)
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def normalize_column_type(type, name)
|
50
|
+
if type.to_s == 'text'
|
51
|
+
:string
|
52
|
+
elsif name.ends_with?('_id')
|
53
|
+
:uuid
|
54
|
+
else
|
55
|
+
type
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'global_registry'
|
4
|
+
|
5
|
+
module GlobalRegistry #:nodoc:
|
6
|
+
module Bindings #:nodoc:
|
7
|
+
module Entity #:nodoc:
|
8
|
+
module EntityTypeMethods
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def push_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.type,
|
16
|
+
'filters[parent_id]' => parent_entity_id)['entity_types']&.first
|
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
|
27
|
+
end
|
28
|
+
|
29
|
+
def push_entity_type_fields(entity_type)
|
30
|
+
existing_fields = entity_type['fields']&.collect { |f| f['name'].to_sym } || []
|
31
|
+
columns_to_push
|
32
|
+
.reject { |k, _v| existing_fields.include? k }
|
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
|
38
|
+
end
|
39
|
+
|
40
|
+
def parent_entity_type_id
|
41
|
+
parent_type = global_registry&.parent_type
|
42
|
+
return if parent_type.blank? || global_registry.parent_is_self?
|
43
|
+
parent_entity_type = global_registry.parent_class.send :push_entity_type
|
44
|
+
parent_entity_type&.dig('id')
|
45
|
+
end
|
46
|
+
|
47
|
+
def entity_type_cache_key
|
48
|
+
"GlobalRegistry::Bindings::EntityType::#{global_registry.type}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'global_registry_bindings/workers/pull_mdm_id_worker'
|
4
|
+
|
5
|
+
module GlobalRegistry #:nodoc:
|
6
|
+
module Bindings #:nodoc:
|
7
|
+
module Entity #:nodoc:
|
8
|
+
module MdmMethods
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
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
|
+
def pull_mdm_id_from_global_registry
|
22
|
+
unless global_registry.id_value?
|
23
|
+
raise GlobalRegistry::Bindings::RecordMissingGlobalRegistryId,
|
24
|
+
"#{self.class.name} #{id} has no #{global_registry.id_column}; will retry"
|
25
|
+
end
|
26
|
+
entity = GlobalRegistry::Entity.find(global_registry.id_value, 'filters[owned_by]' => 'mdm')
|
27
|
+
mdm_entity_id = dig_global_registry_mdm_id_from_entity(entity, global_registry.type.to_s)
|
28
|
+
unless mdm_entity_id
|
29
|
+
raise GlobalRegistry::Bindings::EntityMissingMdmId,
|
30
|
+
"GR entity #{global_registry.id_value} for #{self.class.name} #{id} has no mdm id; will retry"
|
31
|
+
end
|
32
|
+
update_column(global_registry.mdm_id_column, mdm_entity_id) # rubocop:disable Rails/SkipsModelValidations
|
33
|
+
end
|
34
|
+
|
35
|
+
def dig_global_registry_mdm_id_from_entity(entity, type)
|
36
|
+
Array.wrap(entity.dig('entity', type, "master_#{type}:relationship"))
|
37
|
+
.first # although there should not be more than one
|
38
|
+
.try(:[], "master_#{type}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'global_registry_bindings/workers/push_gr_entity_worker'
|
4
|
+
|
5
|
+
module GlobalRegistry #:nodoc:
|
6
|
+
module Bindings #:nodoc:
|
7
|
+
module Entity #:nodoc:
|
8
|
+
module PushEntityMethods
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
after_commit :push_entity_to_global_registry_async, on: (global_registry.push_on - %i[delete])
|
13
|
+
end
|
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
|
21
|
+
|
22
|
+
if global_registry.parent_type.present? && !global_registry.parent_is_self?
|
23
|
+
create_dependent_entity_in_global_registry
|
24
|
+
elsif global_registry.id_value?
|
25
|
+
update_entity_in_global_registry
|
26
|
+
else
|
27
|
+
create_entity_in_global_registry
|
28
|
+
end
|
29
|
+
rescue RestClient::ResourceNotFound
|
30
|
+
global_registry.id_value = nil
|
31
|
+
push_entity_to_global_registry
|
32
|
+
end
|
33
|
+
|
34
|
+
def update_entity_in_global_registry
|
35
|
+
entity_attributes = { global_registry.type => entity_attributes_to_push }
|
36
|
+
GlobalRegistry::Entity.put(global_registry.id_value, entity: entity_attributes)
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_entity_in_global_registry
|
40
|
+
if global_registry.parent_is_self? && global_registry.parent_id_value.blank?
|
41
|
+
# Push parent entity if it exists and is missing global_registry_id
|
42
|
+
global_registry.parent&.create_entity_in_global_registry
|
43
|
+
end
|
44
|
+
entity_attributes = { global_registry.type => entity_attributes_to_push }
|
45
|
+
entity = GlobalRegistry::Entity.post(entity: entity_attributes)
|
46
|
+
global_registry.id_value = dig_global_registry_id_from_entity(entity['entity'], global_registry.type)
|
47
|
+
update_column(global_registry.id_column, # rubocop:disable Rails/SkipsModelValidations
|
48
|
+
global_registry.id_value)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create or Update a child entity (ex: :email_address is a child of :person)
|
52
|
+
def create_dependent_entity_in_global_registry # rubocop:disable Metrics/AbcSize
|
53
|
+
return if global_registry.parent.blank?
|
54
|
+
global_registry.parent.push_entity_to_global_registry if global_registry.parent_id_value.blank?
|
55
|
+
entity_attributes = {
|
56
|
+
global_registry.parent_type => {
|
57
|
+
client_integration_id: global_registry.parent.id,
|
58
|
+
global_registry.type => entity_attributes_to_push
|
59
|
+
}
|
60
|
+
}
|
61
|
+
entity = GlobalRegistry::Entity.put(global_registry.parent_id_value, entity: entity_attributes)
|
62
|
+
global_registry.id_value = dig_global_registry_id_from_entity(entity['entity'],
|
63
|
+
global_registry.type,
|
64
|
+
global_registry.parent_type)
|
65
|
+
update_column(global_registry.id_column, # rubocop:disable Rails/SkipsModelValidations
|
66
|
+
global_registry.id_value)
|
67
|
+
end
|
68
|
+
|
69
|
+
def dig_global_registry_id_from_entity(entity, type, parent_type = nil)
|
70
|
+
return entity&.dig(type.to_s, 'id') unless parent_type
|
71
|
+
Array.wrap(entity&.dig(parent_type.to_s, type.to_s)).detect do |item|
|
72
|
+
item['client_integration_id'] == id.to_s
|
73
|
+
end&.dig('id')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'global_registry'
|
4
|
+
require 'global_registry_bindings/workers/push_relationship_worker'
|
5
|
+
|
6
|
+
module GlobalRegistry #:nodoc:
|
7
|
+
module Bindings #:nodoc:
|
8
|
+
module Entity #:nodoc:
|
9
|
+
module PushRelationshipMethods
|
10
|
+
extend ActiveSupport::Concern
|
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
|
+
def push_relationship_to_global_registry
|
21
|
+
ensure_related_entities_have_global_registry_ids!
|
22
|
+
self.class.push_global_registry_relationship_type
|
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)
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_relationship_in_global_registry # rubocop:disable Metrics/AbcSize
|
36
|
+
entity = GlobalRegistry::Entity.put(global_registry.parent_id_value,
|
37
|
+
{ entity: { global_registry.parent_type => {
|
38
|
+
"#{global_registry.related_relationship_name}:relationship" =>
|
39
|
+
entity_attributes_to_push.merge(global_registry.related_type =>
|
40
|
+
global_registry.related_id_value)
|
41
|
+
}, client_integration_id: global_registry.parent.id } },
|
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?
|
53
|
+
end
|
54
|
+
|
55
|
+
def global_registry_relationship_entity_id_from_entity(entity)
|
56
|
+
relationships = Array.wrap entity.dig('entity', global_registry.parent_type.to_s,
|
57
|
+
"#{global_registry.related_relationship_name}:relationship")
|
58
|
+
relationships.detect do |rel|
|
59
|
+
cid = rel['client_integration_id']
|
60
|
+
cid = cid['value'] if cid.is_a?(Hash)
|
61
|
+
cid == id.to_s
|
62
|
+
end&.dig('relationship_entity_id')
|
63
|
+
end
|
64
|
+
|
65
|
+
def ensure_related_entities_have_global_registry_ids!
|
66
|
+
return if global_registry.parent_id_value.present? && global_registry.related_id_value.present?
|
67
|
+
# Enqueue push_entity worker for related entities missing global_registry_id and retry relationship push
|
68
|
+
names = []
|
69
|
+
[global_registry.parent, global_registry.related].each do |model|
|
70
|
+
next if model.global_registry.id_value?
|
71
|
+
names << "#{model.class.name}(#{model.id})"
|
72
|
+
model.push_entity_to_global_registry_async
|
73
|
+
end
|
74
|
+
raise GlobalRegistry::Bindings::RelatedEntityMissingGlobalRegistryId,
|
75
|
+
"#{self.class.name}(#{id}) has related entities [#{names.join ', '}] missing global_registry_id;" \
|
76
|
+
' will retry.'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|