maestrano-connector-rails 1.2.3 → 1.3.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/.rubocop_todo.yml +7 -20
- data/VERSION +1 -1
- data/app/controllers/maestrano/synchronizations_controller.rb +3 -3
- data/app/models/maestrano/connector/rails/concerns/complex_entity.rb +50 -22
- data/app/models/maestrano/connector/rails/concerns/connec_helper.rb +157 -19
- data/app/models/maestrano/connector/rails/concerns/entity.rb +63 -42
- data/app/models/maestrano/connector/rails/concerns/external.rb +4 -0
- data/app/models/maestrano/connector/rails/concerns/sub_entity_base.rb +18 -5
- data/app/models/maestrano/connector/rails/organization.rb +1 -1
- data/lib/generators/connector/templates/complex_entity_example/contact_and_lead.rb +5 -5
- data/lib/generators/connector/templates/entity.rb +4 -5
- data/lib/generators/connector/templates/external.rb +6 -0
- data/lib/generators/connector/templates/home_index.haml +7 -4
- data/maestrano-connector-rails.gemspec +7 -4
- data/release_notes.md +5 -0
- data/spec/factories.rb +2 -2
- data/spec/integration/complex_id_references_spec.rb +248 -0
- data/spec/integration/complex_naming_spec.rb +191 -0
- data/spec/integration/{integration_complex_spec.rb → complex_spec.rb} +9 -9
- data/spec/integration/connec_to_external_spec.rb +7 -3
- data/spec/integration/id_references_spec.rb +581 -0
- data/spec/integration/singleton_spec.rb +3 -3
- data/spec/models/complex_entity_spec.rb +42 -27
- data/spec/models/connec_helper_spec.rb +399 -31
- data/spec/models/entity_spec.rb +76 -21
- data/spec/models/external_spec.rb +4 -0
- data/spec/models/sub_entity_base_spec.rb +11 -4
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01e80e8ec8f1cf42c1b4dc6e1c55939d010bc8e3
|
4
|
+
data.tar.gz: ad2dc078eb9f605c2bd0a236690801577f38a43b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef502e52b0d613ba02a37ec02db1c248142553c18178008a4cab46e472c86213eff01ba772db527b360b8f190a943df1e69b549a857a7480996db02b68bb7413
|
7
|
+
data.tar.gz: cc32cc071376de85c8e5269c1cbdd4dff33ca20049fedf8711bbd09c56f69b3f21a05d090206bb614a65b6e8a78fd067d6382ec46046a71e34e6727036cd20d9
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2016-07-
|
3
|
+
# on 2016-07-26 04:25:37 +0100 using RuboCop version 0.41.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -19,7 +19,7 @@ Lint/UnusedBlockArgument:
|
|
19
19
|
Exclude:
|
20
20
|
- 'app/jobs/maestrano/connector/rails/synchronization_job.rb'
|
21
21
|
|
22
|
-
# Offense count:
|
22
|
+
# Offense count: 17
|
23
23
|
# Cop supports --auto-correct.
|
24
24
|
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
|
25
25
|
Lint/UnusedMethodArgument:
|
@@ -29,29 +29,23 @@ Lint/UnusedMethodArgument:
|
|
29
29
|
- 'app/models/maestrano/connector/rails/concerns/entity.rb'
|
30
30
|
- 'app/models/maestrano/connector/rails/concerns/external.rb'
|
31
31
|
|
32
|
-
# Offense count:
|
32
|
+
# Offense count: 23
|
33
33
|
Metrics/AbcSize:
|
34
34
|
Max: 70
|
35
35
|
|
36
|
-
# Offense count:
|
36
|
+
# Offense count: 10
|
37
37
|
Metrics/CyclomaticComplexity:
|
38
38
|
Max: 14
|
39
39
|
|
40
|
-
# Offense count:
|
41
|
-
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
|
42
|
-
# URISchemes: http, https
|
43
|
-
Metrics/LineLength:
|
44
|
-
Max: 311
|
45
|
-
|
46
|
-
# Offense count: 16
|
40
|
+
# Offense count: 20
|
47
41
|
# Configuration parameters: CountComments.
|
48
42
|
Metrics/MethodLength:
|
49
43
|
Max: 42
|
50
44
|
|
51
|
-
# Offense count:
|
45
|
+
# Offense count: 2
|
52
46
|
# Configuration parameters: CountComments.
|
53
47
|
Metrics/ModuleLength:
|
54
|
-
Max:
|
48
|
+
Max: 263
|
55
49
|
|
56
50
|
# Offense count: 2
|
57
51
|
# Configuration parameters: CountKeywordArgs.
|
@@ -136,13 +130,6 @@ Style/PredicateName:
|
|
136
130
|
- 'app/helpers/maestrano/connector/rails/session_helper.rb'
|
137
131
|
- 'app/models/maestrano/connector/rails/concerns/entity.rb'
|
138
132
|
|
139
|
-
# Offense count: 1
|
140
|
-
# Cop supports --auto-correct.
|
141
|
-
# Configuration parameters: AllowMultipleReturnValues.
|
142
|
-
Style/RedundantReturn:
|
143
|
-
Exclude:
|
144
|
-
- 'app/jobs/maestrano/connector/rails/push_to_connec_worker.rb'
|
145
|
-
|
146
133
|
# Offense count: 1
|
147
134
|
# Cop supports --auto-correct.
|
148
135
|
Style/RedundantSelf:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
@@ -2,7 +2,7 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
|
|
2
2
|
def show
|
3
3
|
uid = params[:id]
|
4
4
|
organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
|
5
|
-
return render json: {errors: {message: "Organization not found", code: 404}}, status: :not_found unless organization
|
5
|
+
return render json: {errors: [{message: "Organization not found", code: 404}]}, status: :not_found unless organization
|
6
6
|
|
7
7
|
h = {
|
8
8
|
group_id: organization.uid,
|
@@ -25,7 +25,7 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
|
|
25
25
|
uid = params[:group_id]
|
26
26
|
opts = params[:opts] || {}
|
27
27
|
organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
|
28
|
-
return render json: {errors: {message: "Organization not found", code: 404}}, status: :not_found unless organization
|
28
|
+
return render json: {errors: [{message: "Organization not found", code: 404}]}, status: :not_found unless organization
|
29
29
|
|
30
30
|
Maestrano::Connector::Rails::SynchronizationJob.perform_later(organization, opts.with_indifferent_access)
|
31
31
|
head :created
|
@@ -34,7 +34,7 @@ class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookControlle
|
|
34
34
|
def toggle_sync
|
35
35
|
uid = params[:group_id]
|
36
36
|
organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
|
37
|
-
return render json: {errors: {message: "Organization not found", code: 404}}, status: :not_found unless organization
|
37
|
+
return render json: {errors: [{message: "Organization not found", code: 404}]}, status: :not_found unless organization
|
38
38
|
|
39
39
|
organization.toggle(:sync_enabled)
|
40
40
|
organization.save
|
@@ -14,6 +14,19 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
14
14
|
raise 'Not implemented'
|
15
15
|
end
|
16
16
|
|
17
|
+
def formatted_external_entities_names
|
18
|
+
formatted_entities_names(external_entities_names)
|
19
|
+
end
|
20
|
+
|
21
|
+
def formatted_connec_entities_names
|
22
|
+
formatted_entities_names(connec_entities_names)
|
23
|
+
end
|
24
|
+
|
25
|
+
def formatted_entities_names(names)
|
26
|
+
return names.with_indifferent_access if names.is_a?(Hash)
|
27
|
+
names.index_by { |name| name }.with_indifferent_access
|
28
|
+
end
|
29
|
+
|
17
30
|
def count_entities(entities)
|
18
31
|
entities.values.map(&:size).max
|
19
32
|
end
|
@@ -59,54 +72,54 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
59
72
|
def get_connec_entities(last_synchronization_date = nil)
|
60
73
|
entities = ActiveSupport::HashWithIndifferentAccess.new
|
61
74
|
|
62
|
-
self.class.
|
63
|
-
sub_entity_instance = instantiate_sub_entity_instance(
|
75
|
+
self.class.formatted_connec_entities_names.each do |connec_entity_name, connec_class_name|
|
76
|
+
sub_entity_instance = instantiate_sub_entity_instance(connec_class_name)
|
64
77
|
entities[connec_entity_name] = sub_entity_instance.get_connec_entities(last_synchronization_date)
|
65
78
|
end
|
66
79
|
entities
|
67
80
|
end
|
68
81
|
|
69
|
-
def get_external_entities_wrapper(last_synchronization_date = nil)
|
82
|
+
def get_external_entities_wrapper(last_synchronization_date = nil, entity_name = '')
|
70
83
|
entities = ActiveSupport::HashWithIndifferentAccess.new
|
71
84
|
|
72
|
-
self.class.
|
73
|
-
sub_entity_instance = instantiate_sub_entity_instance(
|
74
|
-
entities[external_entity_name] = sub_entity_instance.get_external_entities_wrapper(last_synchronization_date)
|
85
|
+
self.class.formatted_external_entities_names.each do |external_entity_name, external_class_name|
|
86
|
+
sub_entity_instance = instantiate_sub_entity_instance(external_class_name)
|
87
|
+
entities[external_entity_name] = sub_entity_instance.get_external_entities_wrapper(last_synchronization_date, external_entity_name)
|
75
88
|
end
|
76
89
|
entities
|
77
90
|
end
|
78
91
|
|
79
92
|
def consolidate_and_map_data(connec_entities, external_entities)
|
80
|
-
|
81
|
-
|
93
|
+
modelled_external_entities = external_model_to_connec_model(external_entities)
|
94
|
+
modelled_connec_entities = connec_model_to_external_model(connec_entities)
|
82
95
|
|
83
|
-
mapped_connec_entities = consolidate_and_map_connec_entities(
|
84
|
-
mapped_external_entities = consolidate_and_map_external_entities(
|
96
|
+
mapped_connec_entities = consolidate_and_map_connec_entities(modelled_connec_entities, modelled_external_entities)
|
97
|
+
mapped_external_entities = consolidate_and_map_external_entities(modelled_external_entities)
|
85
98
|
|
86
99
|
{connec_entities: mapped_connec_entities, external_entities: mapped_external_entities}
|
87
100
|
end
|
88
101
|
|
89
|
-
def consolidate_and_map_connec_entities(
|
90
|
-
|
102
|
+
def consolidate_and_map_connec_entities(modelled_connec_entities, modelled_external_entities)
|
103
|
+
modelled_connec_entities.each do |connec_entity_name, entities_in_external_model|
|
91
104
|
entities_in_external_model.each do |external_entity_name, entities|
|
92
|
-
sub_entity_instance = instantiate_sub_entity_instance(connec_entity_name)
|
93
|
-
equivalent_external_entities = (
|
105
|
+
sub_entity_instance = instantiate_sub_entity_instance(self.class.formatted_connec_entities_names[connec_entity_name])
|
106
|
+
equivalent_external_entities = (modelled_external_entities[external_entity_name] && modelled_external_entities[external_entity_name][connec_entity_name]) || []
|
94
107
|
|
95
108
|
entities_in_external_model[external_entity_name] = sub_entity_instance.consolidate_and_map_connec_entities(entities, equivalent_external_entities, sub_entity_instance.class.references[external_entity_name] || [], external_entity_name)
|
96
109
|
end
|
97
110
|
end
|
98
|
-
|
111
|
+
modelled_connec_entities
|
99
112
|
end
|
100
113
|
|
101
|
-
def consolidate_and_map_external_entities(
|
102
|
-
|
114
|
+
def consolidate_and_map_external_entities(modelled_external_entities)
|
115
|
+
modelled_external_entities.each do |external_entity_name, entities_in_connec_model|
|
103
116
|
entities_in_connec_model.each do |connec_entity_name, entities|
|
104
|
-
sub_entity_instance = instantiate_sub_entity_instance(external_entity_name)
|
117
|
+
sub_entity_instance = instantiate_sub_entity_instance(self.class.formatted_external_entities_names[external_entity_name])
|
105
118
|
|
106
119
|
entities_in_connec_model[connec_entity_name] = sub_entity_instance.consolidate_and_map_external_entities(entities, connec_entity_name)
|
107
120
|
end
|
108
121
|
end
|
109
|
-
|
122
|
+
modelled_external_entities
|
110
123
|
end
|
111
124
|
|
112
125
|
# input : {
|
@@ -120,7 +133,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
120
133
|
# }
|
121
134
|
def push_entities_to_connec(mapped_external_entities_with_idmaps)
|
122
135
|
mapped_external_entities_with_idmaps.each do |external_entity_name, entities_in_connec_model|
|
123
|
-
sub_entity_instance = instantiate_sub_entity_instance(external_entity_name)
|
136
|
+
sub_entity_instance = instantiate_sub_entity_instance(self.class.formatted_external_entities_names[external_entity_name])
|
124
137
|
entities_in_connec_model.each do |connec_entity_name, mapped_entities_with_idmaps|
|
125
138
|
sub_entity_instance.push_entities_to_connec_to(mapped_entities_with_idmaps, connec_entity_name)
|
126
139
|
end
|
@@ -129,7 +142,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
129
142
|
|
130
143
|
def push_entities_to_external(mapped_connec_entities_with_idmaps)
|
131
144
|
mapped_connec_entities_with_idmaps.each do |connec_entity_name, entities_in_external_model|
|
132
|
-
sub_entity_instance = instantiate_sub_entity_instance(connec_entity_name)
|
145
|
+
sub_entity_instance = instantiate_sub_entity_instance(self.class.formatted_connec_entities_names[connec_entity_name])
|
133
146
|
entities_in_external_model.each do |external_entity_name, mapped_entities_with_idmaps|
|
134
147
|
sub_entity_instance.push_entities_to_external_to(mapped_entities_with_idmaps, external_entity_name)
|
135
148
|
end
|
@@ -137,7 +150,7 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
137
150
|
end
|
138
151
|
|
139
152
|
def instantiate_sub_entity_instance(entity_name)
|
140
|
-
|
153
|
+
self.class.instantiate_sub_entity_instance(entity_name, @organization, @connec_client, @external_client, @opts)
|
141
154
|
end
|
142
155
|
|
143
156
|
# -------------------------------------------------------------
|
@@ -154,5 +167,20 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
154
167
|
def build_hash_with_entities(entities_name, entity_name, proc, entities)
|
155
168
|
Hash[*entities_name.collect { |name| proc.call(name) == entity_name ? [name, entities] : [name, []] }.flatten(1)]
|
156
169
|
end
|
170
|
+
|
171
|
+
def instantiate_sub_entity_instance(entity_name, organization, connec_client, external_client, opts)
|
172
|
+
"Entities::SubEntities::#{entity_name.titleize.split.join}".constantize.new(organization, connec_client, external_client, opts)
|
173
|
+
end
|
174
|
+
|
175
|
+
def find_complex_entity_and_instantiate_external_sub_entity_instance(entity_name, organization, connec_client, external_client, opts)
|
176
|
+
Maestrano::Connector::Rails::External.entities_list.each do |entity_name_from_list|
|
177
|
+
clazz = "Entities::#{entity_name_from_list.singularize.titleize.split.join}".constantize
|
178
|
+
if clazz.methods.include?('external_entities_names'.to_sym)
|
179
|
+
formatted_names = clazz.formatted_external_entities_names
|
180
|
+
return instantiate_sub_entity_instance(formatted_names[entity_name], organization, connec_client, external_client, opts) if formatted_names[entity_name]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
nil
|
184
|
+
end
|
157
185
|
end
|
158
186
|
end
|
@@ -17,6 +17,8 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
17
17
|
client
|
18
18
|
end
|
19
19
|
|
20
|
+
# Returns a string of the tenant's current connec version.
|
21
|
+
# Can use Gem::Version for version comparison
|
20
22
|
def connec_version(organization)
|
21
23
|
@@connec_version = Rails.cache.fetch("connec_version_#{organization.tenant}", namespace: 'maestrano', expires_in: 1.day) do
|
22
24
|
response = get_client(organization).class.get("#{Maestrano[organization.tenant].param('connec.host')}/version")
|
@@ -26,32 +28,52 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
26
28
|
@@connec_version
|
27
29
|
end
|
28
30
|
|
29
|
-
#
|
30
|
-
#
|
31
|
+
# Replaces the arrays of id received from Connec! by the id of the external application
|
32
|
+
# Returns a hash {entity: {}, connec_id: '', id_refs_only_connec_entity: {}}
|
33
|
+
# If an array has no id for this oauth_provider and oauth_uid but has one for connec, it returns a nil entity (skip the record)
|
31
34
|
def unfold_references(connec_entity, references, organization)
|
32
|
-
|
35
|
+
references = format_references(references)
|
36
|
+
unfolded_connec_entity = connec_entity.deep_dup.with_indifferent_access
|
33
37
|
not_nil = true
|
34
38
|
|
35
39
|
# Id
|
36
40
|
id_hash = unfolded_connec_entity['id'].find { |id| id['provider'] == organization.oauth_provider && id['realm'] == organization.oauth_uid }
|
37
|
-
|
41
|
+
connec_id = unfolded_connec_entity['id'].find { |id| id['provider'] == 'connec' }['id']
|
38
42
|
unfolded_connec_entity['id'] = id_hash ? id_hash['id'] : nil
|
39
43
|
|
40
|
-
# Other
|
41
|
-
references
|
42
|
-
|
44
|
+
# Other references
|
45
|
+
# Record references are references to other records (organization_id, item_id, ...)
|
46
|
+
references[:record_references].each do |reference|
|
47
|
+
not_nil &= unfold_references_helper(unfolded_connec_entity, reference.split('/'), organization)
|
43
48
|
end
|
44
|
-
|
49
|
+
# Id references are references to sub entities ids (invoice lines id, ...)
|
50
|
+
# We do not return nil if we're missing an id reference
|
51
|
+
references[:id_references].each do |reference|
|
52
|
+
unfold_references_helper(unfolded_connec_entity, reference.split('/'), organization)
|
53
|
+
end
|
54
|
+
unfolded_connec_entity = not_nil ? unfolded_connec_entity : nil
|
55
|
+
|
56
|
+
# Filter the connec entity to keep only the id_references fields (in order to save some memory)
|
57
|
+
# Give an empty hash if there's nothing left
|
58
|
+
id_refs_only_connec_entity = filter_connec_entity_for_id_refs(connec_entity, references[:id_references])
|
59
|
+
|
60
|
+
{entity: unfolded_connec_entity, connec_id: connec_id, id_refs_only_connec_entity: id_refs_only_connec_entity}
|
45
61
|
end
|
46
62
|
|
63
|
+
# Replaces ids from the external application by arrays containing them
|
47
64
|
def fold_references(mapped_external_entity, references, organization)
|
65
|
+
references = format_references(references)
|
48
66
|
mapped_external_entity = mapped_external_entity.with_indifferent_access
|
49
|
-
|
67
|
+
|
68
|
+
# Use both record_references and id_references + the id
|
69
|
+
(references.values.flatten + ['id']).each do |reference|
|
50
70
|
fold_references_helper(mapped_external_entity, reference.split('/'), organization)
|
51
71
|
end
|
72
|
+
|
52
73
|
mapped_external_entity
|
53
74
|
end
|
54
75
|
|
76
|
+
# Builds an id_hash from the id and organization
|
55
77
|
def id_hash(id, organization)
|
56
78
|
{
|
57
79
|
id: id,
|
@@ -60,6 +82,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
60
82
|
}
|
61
83
|
end
|
62
84
|
|
85
|
+
# Recursive method for folding references
|
63
86
|
def fold_references_helper(entity, array_of_refs, organization)
|
64
87
|
ref = array_of_refs.shift
|
65
88
|
field = entity[ref]
|
@@ -71,7 +94,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
71
94
|
field.each do |f|
|
72
95
|
fold_references_helper(f, array_of_refs.dup, organization)
|
73
96
|
end
|
74
|
-
when
|
97
|
+
when Hash
|
75
98
|
fold_references_helper(entity[ref], array_of_refs, organization)
|
76
99
|
else
|
77
100
|
id = field
|
@@ -79,6 +102,7 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
79
102
|
end
|
80
103
|
end
|
81
104
|
|
105
|
+
# Recursive method for unfolding references
|
82
106
|
def unfold_references_helper(entity, array_of_refs, organization)
|
83
107
|
ref = array_of_refs.shift
|
84
108
|
field = entity[ref]
|
@@ -93,23 +117,137 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
93
117
|
# We may enqueue a fetch on the endpoint of the missing association, followed by a re-fetch on this one.
|
94
118
|
# However it's expected to be an edge case, so for now we rely on the fact that the webhooks should be relativly in order.
|
95
119
|
# Worst case it'll be done on following sync
|
120
|
+
entity.delete(ref)
|
96
121
|
return nil
|
97
122
|
end
|
123
|
+
true
|
98
124
|
|
99
125
|
# Follow embedment path
|
100
126
|
else
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
127
|
+
return true if field.blank?
|
128
|
+
case field
|
129
|
+
when Array
|
130
|
+
bool = true
|
131
|
+
field.each do |f|
|
132
|
+
bool &= unfold_references_helper(f, array_of_refs.dup, organization)
|
133
|
+
end
|
134
|
+
bool
|
135
|
+
when Hash
|
136
|
+
unfold_references_helper(entity[ref], array_of_refs, organization)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Transforms the references into an hash {record_references: [], id_references: []}
|
142
|
+
# References can either be an array (only record references), or a hash
|
143
|
+
def format_references(references)
|
144
|
+
return {record_references: references, id_references: []} if references.is_a?(Array)
|
145
|
+
references[:record_references] ||= []
|
146
|
+
references[:id_references] ||= []
|
147
|
+
references
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns the connec_entity without all the fields that are not id_references
|
151
|
+
def filter_connec_entity_for_id_refs(connec_entity, id_references)
|
152
|
+
return {} if id_references.empty?
|
153
|
+
|
154
|
+
entity = connec_entity.dup.with_indifferent_access
|
155
|
+
tree = build_id_references_tree(id_references)
|
156
|
+
|
157
|
+
filter_connec_entity_for_id_refs_helper(entity, tree)
|
158
|
+
|
159
|
+
# TODO, improve performance by returning an empty hash if all the id_references have their id in the connec hash
|
160
|
+
# We should still return all of them if at least one is missing as we are relying on the id
|
161
|
+
entity
|
162
|
+
end
|
163
|
+
|
164
|
+
# Recursive method for filtering connec entities
|
165
|
+
def filter_connec_entity_for_id_refs_helper(entity_hash, tree)
|
166
|
+
return if tree.empty?
|
167
|
+
entity_hash.slice!(*tree.keys)
|
168
|
+
|
169
|
+
tree.each do |key, children|
|
170
|
+
case entity_hash[key]
|
171
|
+
when Array
|
172
|
+
entity_hash[key].each do |hash|
|
173
|
+
filter_connec_entity_for_id_refs_helper(hash, children)
|
174
|
+
end
|
175
|
+
when Hash
|
176
|
+
filter_connec_entity_for_id_refs_helper(entity_hash[key], children)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Builds a tree from an array of id_references
|
182
|
+
# input: %w(lines/id lines/linked/id linked/id)
|
183
|
+
# output: {"lines"=>{"id"=>{}, "linked"=>{"id"=>{}}}, "linked"=>{"id"=>{}}}
|
184
|
+
def build_id_references_tree(id_references)
|
185
|
+
tree = {}
|
186
|
+
|
187
|
+
id_references.each do |id_reference|
|
188
|
+
array_of_refs = id_reference.split('/')
|
189
|
+
|
190
|
+
t = tree
|
191
|
+
array_of_refs.each do |ref|
|
192
|
+
t[ref] ||= {}
|
193
|
+
t = t[ref]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
tree
|
198
|
+
end
|
199
|
+
|
200
|
+
# Merges the id arrays from two hashes while keeping only the id_references fields
|
201
|
+
def merge_id_hashes(dist, src, id_references)
|
202
|
+
dist = dist.with_indifferent_access
|
203
|
+
src = src.with_indifferent_access
|
204
|
+
|
205
|
+
id_references.each do |id_reference|
|
206
|
+
array_of_refs = id_reference.split('/')
|
207
|
+
|
208
|
+
merge_id_hashes_helper(dist, array_of_refs, src)
|
209
|
+
end
|
210
|
+
|
211
|
+
dist
|
212
|
+
end
|
213
|
+
|
214
|
+
# Recursive helper for merging id hashes
|
215
|
+
def merge_id_hashes_helper(hash, array_of_refs, src, path = [])
|
216
|
+
ref = array_of_refs.shift
|
217
|
+
field = hash[ref]
|
218
|
+
|
219
|
+
if array_of_refs.empty? && field
|
220
|
+
value = value_from_hash(src, path + [ref])
|
221
|
+
if value.is_a?(Array)
|
222
|
+
hash[ref] = (field + value).uniq
|
223
|
+
else
|
224
|
+
hash.delete(ref)
|
225
|
+
end
|
226
|
+
else
|
227
|
+
case field
|
228
|
+
when Array
|
229
|
+
field.each_with_index do |f, index|
|
230
|
+
merge_id_hashes_helper(f, array_of_refs.dup, src, path + [ref, index])
|
109
231
|
end
|
232
|
+
when Hash
|
233
|
+
merge_id_hashes_helper(field, array_of_refs, src, path + [ref])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Returns the value from a hash following the given path
|
239
|
+
# Path sould be an array like [:lines, 0, :id]
|
240
|
+
def value_from_hash(hash, path)
|
241
|
+
value = hash
|
242
|
+
|
243
|
+
begin
|
244
|
+
path.each do |p|
|
245
|
+
value = value[p]
|
110
246
|
end
|
247
|
+
value
|
248
|
+
rescue NoMethodError
|
249
|
+
nil
|
111
250
|
end
|
112
|
-
true
|
113
251
|
end
|
114
252
|
end
|
115
253
|
end
|