activefacts-compositions 1.9.10 → 1.9.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,6 +10,12 @@ require "activefacts/compositions/relational"
10
10
  module ActiveFacts
11
11
  module Compositions
12
12
  class DataVault < Relational
13
+ BDV_ANNOTATIONS = /same as link|hierarchy link|computed link|exploration link|computed satellite|point in time|bridge/
14
+ BDV_LINK_ANNOTATIONS = /same as link|hierarchy link|computed link|exploration link/
15
+ BDV_SAT_ANNOTATIONS = /computed satellite/
16
+ BDV_PIT_ANNOTATIONS = /point in time/
17
+ BDV_BRIDGE_ANNOTATIONS = /bridge/
18
+
13
19
  public
14
20
  def self.options
15
21
  {
@@ -19,8 +25,11 @@ module ActiveFacts
19
25
  hubname: ['String', "Suffix or pattern for naming hub tables. Include a + to insert the name. Default 'HUB'"],
20
26
  linkname: ['String', "Suffix or pattern for naming link tables. Include a + to insert the name. Default 'LINK'"],
21
27
  satname: ['String', "Suffix or pattern for naming satellite tables. Include a + to insert the name. Default 'SAT'"],
28
+ pitname: ['String', "Suffix or pattern for naming point in time tables. Include a + to insert the name. Default 'PIT'"],
29
+ bridgename: ['String', "Suffix or pattern for naming bridge tables. Include a + to insert the name. Default 'BRIDGE'"],
22
30
  refname: ['String', "Suffix or pattern for naming reference tables. Include a + to insert the name. Default '+'"],
23
- }
31
+ }.merge(Relational.options).
32
+ reject{|k,v| [:surrogates].include?(k) } # Datavault surrogates are not optional
24
33
  end
25
34
 
26
35
  def initialize constellation, name, options = {}
@@ -34,10 +43,14 @@ module ActiveFacts
34
43
  @option_link_name.sub!(/^/,'+ ') unless @option_link_name =~ /\+/
35
44
  @option_sat_name = options.delete('satname') || 'SAT'
36
45
  @option_sat_name.sub!(/^/,'+ ') unless @option_sat_name =~ /\+/
46
+ @option_pit_name = options.delete('refname') || 'PIT'
47
+ @option_pit_name.sub!(/^/,'+ ') unless @option_ref_name =~ /\+/
48
+ @option_bridge_name = options.delete('refname') || 'BRIDGE'
49
+ @option_bridge_name.sub!(/^/,'+ ') unless @option_ref_name =~ /\+/
37
50
  @option_ref_name = options.delete('refname') || 'REF'
38
51
  @option_ref_name.sub!(/^/,'+ ') unless @option_ref_name =~ /\+/
39
52
 
40
- super constellation, name, options
53
+ super constellation, name, options, 'DataVault'
41
54
 
42
55
  @option_surrogates = true # Always inject surrogates regardless of superclass
43
56
  end
@@ -51,10 +64,20 @@ module ActiveFacts
51
64
 
52
65
  def composite_is_reference composite
53
66
  object_type = composite.mapping.object_type
54
- object_type.concept.all_concept_annotation.detect{|ca| ca.mapping_annotation == 'static'} or
67
+ all_ca = object_type.concept.all_concept_annotation
68
+
69
+ all_ca.detect{|ca| ca.mapping_annotation == 'static'} or
55
70
  !object_type.is_a?(ActiveFacts::Metamodel::EntityType)
56
71
  end
57
72
 
73
+ def composite_is_bdv composite
74
+ object_type = composite.mapping.object_type
75
+ all_ca = object_type.concept.all_concept_annotation
76
+
77
+ trace :datavault, "composite #{composite.mapping.name} annotations #{all_ca.map{|ca| ca.mapping_annotation} *' '}"
78
+ all_ca.detect{|ca| ca.mapping_annotation =~ BDV_ANNOTATIONS}
79
+ end
80
+
58
81
  # Data Vaults need a surrogate key on every Hub and Link.
59
82
  # Don't add a surrogate on a Reference table!
60
83
  def needs_surrogate(composite)
@@ -74,72 +97,151 @@ module ActiveFacts
74
97
  def classify_composites
75
98
  detect_reference_tables
76
99
 
77
- trace :datavault, "Classify non-reference tables into hubs and links" do
100
+ @bdv_composites, @rdv_composites =
101
+ @non_reference_composites.partition { |composite| composite_is_bdv(composite) }
102
+
103
+ trace :datavault, "Classify non-reference composites into hubs, links, pits and bridges" do
78
104
  # Make an initial determination, then adjust for foreign keys to links afterwards
105
+ @hub_composites = []
106
+ @link_composites = []
107
+ @sat_composites = []
108
+ @bdv_link_composites = []
109
+ @bdv_sat_composites = []
110
+ @pit_composites = []
111
+ @bridge_composites = []
79
112
  @key_structure = {}
80
- @link_composites, @hub_composites =
81
- @non_reference_composites.
82
- sort_by{|c| c.mapping.name}.
83
- partition do |composite|
84
- trace :datavault, "Decide whether #{composite.mapping.name} is a link or a hub" do
85
- @key_structure[composite] =
86
- mapped_to =
87
- composite_key_structure composite
88
-
89
- # It's a Link if the preferred identifier includes more than non_reference_composite.
90
- mapped_to.compact.size > 1
91
- end
92
- end
113
+ @links_as_hubs = {}
114
+ @pit_hub = {}
115
+ @pit_members = {}
116
+ @pit_satellite = {}
117
+
118
+ rdv_classify_composites
119
+ bdv_classify_composites
120
+
121
+ trace :datavault_classification!, "Data Vault classification of composites:" do
122
+ trace :datavault, "Reference: #{@reference_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
123
+ trace :datavault, "Raw: #{@rdv_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
124
+ trace :datavault, "Business: #{@bdv_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
125
+ trace :datavault, "Hub: #{@hub_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
126
+ trace :datavault, "Link: #{@link_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
127
+ trace :datavault, "BDV Link: #{@bdv_link_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
128
+ trace :datavault, "BDV Sat: #{@bdv_sat_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
129
+ trace :datavault, "PIT: #{@pit_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
130
+ trace :datavault, "Bridge: #{@bridge_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
131
+ end
132
+ end
133
+ end
93
134
 
94
- trace :datavault, "Checking for foreign keys that reference links" do
95
- # Links may never be the target of a foreign key.
96
- # Any such links must be defined as hubs instead.
97
- @links_as_hubs = {}
98
- fk_dependencies_by_target = {}
99
- fk_dependencies_by_source = {}
100
- (@hub_composites+@link_composites).
101
- each do |composite|
102
- target_composites = enumerate_foreign_keys composite.mapping
103
- target_composites.each do |target_composite|
104
- next if @reference_composites.include?(target_composite)
105
- (fk_dependencies_by_target[target_composite] ||= []) << composite
106
- (fk_dependencies_by_source[composite] ||= []) << target_composite
135
+ def bdv_classify_composites
136
+ # Classify the business links and bridges
137
+ @bdv_composites.sort_by{|c| c.mapping.name}.each do |composite|
138
+ trace :datavault, "Decide whether #{composite.mapping.name} is a link or bridge"
139
+ object_type = composite.mapping.object_type
140
+ composite.composite_group = 'bdv'
141
+ mapped_to = object_type.fact_type.all_role.to_a
142
+ trace :datavault, "#{composite.mapping.name} encloses foreign keys to #{mapped_to.inspect}" unless mapped_to.compact.empty?
143
+
144
+ all_ca = composite.mapping.object_type.concept.all_concept_annotation
145
+ if all_ca.detect{ |ca| ca.mapping_annotation =~ BDV_LINK_ANNOTATIONS}
146
+ @bdv_link_composites << composite
147
+ elsif all_ca.detect{ |ca| ca.mapping_annotation =~ BDV_BRIDGE_ANNOTATIONS}
148
+ @bridge_composites << composite
149
+ end
150
+ end
151
+
152
+ # Classify the point in time tables
153
+ @rdv_composites.sort_by{|c| c.mapping.name}.each do |composite|
154
+ composite.composite_group = 'rdv'
155
+ trace :datavault, "Decide whether #{composite.mapping.name} has point in time table"
156
+
157
+ pit_members = composite.mapping.all_member.select do |member|
158
+ if member.is_a?(MM::Absorption)
159
+ if found_pit = check_pit(member)
160
+ trace :datavault, "Found PIT member #{member.child_role.object_type.name}"
107
161
  end
162
+ found_pit
163
+ else
164
+ false
108
165
  end
166
+ end
109
167
 
110
- fk_dependencies_by_target.keys.each do |target_composite|
111
- if @link_composites.delete(target_composite)
112
- trace :datavault, "Link #{target_composite.inspect} must be a hub because foreign keys reference it"
113
- @hub_composites << target_composite
114
- @links_as_hubs[target_composite] = true
115
- end
168
+ if pit_members.size > 0
169
+ pit_composite = create_pit(composite.mapping.name, composite)
170
+ @pit_composites << pit_composite
171
+ @pit_hub[pit_composite] = composite
172
+ @pit_members[pit_composite] = pit_members
173
+ end
174
+ end
175
+ end
176
+
177
+ def check_pit component
178
+ all_pc = component.parent_role.all_role_ref.map(&:role_sequence).uniq.flat_map(&:all_presence_constraint).uniq
179
+ all_pc.detect do |pc|
180
+ pc.concept.all_concept_annotation.detect{ |ca| ca.mapping_annotation =~ BDV_PIT_ANNOTATIONS}
181
+ end
182
+ end
183
+
184
+ # Create a new PIT for the same object_type as this composite
185
+ def create_pit name, composite
186
+ mapping = @constellation.Mapping(:new, name: name, object_type: composite.mapping.object_type)
187
+ @constellation.Composite(mapping, composition: @composition, composite_group: 'bdv')
188
+ end
189
+
190
+ def rdv_classify_composites
191
+ @link_composites, @hub_composites =
192
+ @rdv_composites.
193
+ sort_by{|c| c.mapping.name}.
194
+ partition do |composite|
195
+ trace :datavault, "Decide whether #{composite.mapping.name} is a link or a hub" do
196
+ @key_structure[composite] =
197
+ mapped_to =
198
+ composite_key_structure composite
199
+
200
+ # It's a Link if the preferred identifier includes more than non_reference_composite.
201
+ mapped_to.compact.size > 1
116
202
  end
203
+ end
117
204
 
118
- begin
119
- converted =
120
- @link_composites.select do |composite|
121
- targets = fk_dependencies_by_source[composite]
122
- id_targets = composite_key_structure(composite).compact
123
- next if targets.size == id_targets.size
124
- trace :datavault, "Link #{composite.mapping.name} must be a hub because it has non-identifying FK references"
125
- @link_composites.delete(composite)
126
- @hub_composites << composite
127
- @links_as_hubs[composite] = true
128
- end
129
- end while converted.size > 0
205
+ trace :datavault, "Checking for foreign keys that reference links" do
206
+ # Links may never be the target of a foreign key.
207
+ # Any such links must be defined as hubs instead.
208
+
209
+ fk_dependencies_by_target = {}
210
+ fk_dependencies_by_source = {}
211
+ (@hub_composites+@link_composites).each do |composite|
212
+ target_composites = enumerate_foreign_keys composite.mapping
213
+ target_composites.each do |target_composite|
214
+ next if @reference_composites.include?(target_composite)
215
+ (fk_dependencies_by_target[target_composite] ||= []) << composite
216
+ (fk_dependencies_by_source[composite] ||= []) << target_composite
217
+ end
218
+ end
130
219
 
220
+ fk_dependencies_by_target.keys.each do |target_composite|
221
+ if @link_composites.delete(target_composite)
222
+ trace :datavault, "Link #{target_composite.inspect} must be a hub because foreign keys reference it"
223
+ @hub_composites << target_composite
224
+ @links_as_hubs[target_composite] = true
225
+ end
131
226
  end
132
227
 
228
+ begin
229
+ converted =
230
+ @link_composites.select do |composite|
231
+ targets = fk_dependencies_by_source[composite]
232
+ id_targets = composite_key_structure(composite).compact
233
+ next if targets.size == id_targets.size
234
+ trace :datavault, "Link #{composite.mapping.name} must be a hub because it has non-identifying FK references"
235
+ @link_composites.delete(composite)
236
+ @hub_composites << composite
237
+ @links_as_hubs[composite] = true
238
+ end
239
+ end while converted.size > 0
240
+
133
241
  # Note: We may still have hubs whose identifiers contain foreign keys to one or more other hubs.
134
242
  # REVISIT: These foreign keys will be deleted so these hubs stand alone,
135
243
  # but have been re-instated as new links to the referenced hubs.
136
244
  end
137
-
138
- trace :datavault_classification!, "Data Vault classification of composites:" do
139
- trace :datavault, "Reference: #{@reference_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
140
- trace :datavault, "Hub: #{@hub_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
141
- trace :datavault, "Link: #{@link_composites.map(&:mapping).map(&:object_type).map(&:name)*', '}"
142
- end
143
245
  end
144
246
 
145
247
  def detect_reference_tables
@@ -148,19 +250,57 @@ module ActiveFacts
148
250
  initial_composites.partition { |composite| composite_is_reference(composite) }
149
251
  end
150
252
 
253
+ def composite_key_structure composite
254
+ # We know that composite.mapping.object_type is an EntityType because all ValueType composites are reference tables
255
+ object_type = composite.mapping.object_type
256
+
257
+ mapped_to =
258
+ object_type.preferred_identifier.role_sequence.all_role_ref_in_order.map do |role_ref|
259
+ player = role_ref.role.object_type
260
+ next nil if player == object_type && role_ref.role.fact_type.all_role.size == 1 # Unaries.
261
+ candidate = @candidates[player]
262
+ next nil unless candidate
263
+ # Take care of full absorption
264
+ while candidate.full_absorption
265
+ candidate = candidate.full_absorption.composition
266
+ end
267
+ @non_reference_composites.include?(c = candidate.mapping.composite) ? c : nil
268
+ end
269
+
270
+ trace :datavault, "Preferred identifier for #{composite.mapping.name} encloses foreign keys to #{mapped_to.inspect}" unless mapped_to.compact.empty?
271
+
272
+ number_of_keys = mapped_to.compact.size
273
+ number_of_values = mapped_to.size-number_of_keys
274
+ trace :datavault_classify,
275
+ if number_of_keys > 1
276
+ # Links have more than one FK to a hub in their key
277
+ "Link #{composite.mapping.name} links #{mapped_to.compact.inspect} with #{number_of_values} values"
278
+ elsif number_of_keys == 1 && number_of_values > 0
279
+ # This is a new hub with a composite key - but we will have to eliminate the foreign key to the base hub
280
+ "Augmented Hub #{composite.mapping.name} has a hub link to #{mapped_to.compact[0].inspect} and #{number_of_values} values"
281
+ elsif number_of_keys == 1
282
+ # This is a new hub with a single-part key that references another hub.
283
+ "Dependent Hub #{composite.mapping.name} is identified by another hub: #{mapped_to.compact[0].inspect}"
284
+ else
285
+ "Hub #{composite.mapping.name} has #{mapped_to.size} parts in its key"
286
+ end
287
+
288
+ mapped_to
289
+ end
290
+
151
291
  def devolve_all
152
292
  delete_reference_table_foreign_keys
153
293
 
154
294
  # For each hub and link, move each non-identifying member
155
295
  # to a new satellite or promote it to a new link.
156
-
157
- @non_reference_composites.
158
- each do |composite|
296
+ (@hub_composites + @link_composites).each do |composite|
159
297
  devolve composite
160
298
  end
161
299
 
300
+ # Rename parents for rdv and bdv
162
301
  rename_parents
163
302
 
303
+ # inject datetime and record source for rdv hubs and links
164
304
  inject_all_datetime_recordsource
165
305
 
166
306
  unless @option_reference
@@ -180,6 +320,78 @@ module ActiveFacts
180
320
 
181
321
  @constellation.loggers.pop if trace :reference_retraction
182
322
  end
323
+
324
+ # Devolve point in time tables, if any
325
+ @pit_composites.each do |composite|
326
+ devolve_pit(composite)
327
+ end
328
+
329
+ end
330
+
331
+ def devolve_pit(pit_composite)
332
+ # inject standard PIT components: surrogate key, hub hash key and snapshot date time
333
+ inject_surrogate(pit_composite)
334
+
335
+ hub_composite = @pit_hub[pit_composite]
336
+ hub_hash_field = hub_composite.primary_index.all_index_field.single.component
337
+ pit_hub_field = hub_hash_field.fork_to_new_parent(pit_composite.mapping)
338
+ date_field = @constellation.ValidFrom(:new,
339
+ parent: pit_composite.mapping,
340
+ name: "Snapshot"+datestamp_type_name,
341
+ object_type: datestamp_type
342
+ )
343
+
344
+ natural_index =
345
+ @constellation.Index(:new, composite: pit_composite, is_unique: true,
346
+ presence_constraint: nil, composite_as_natural_index: pit_composite #, composite_as_primary_index: pit_composite
347
+ )
348
+ @constellation.IndexField(access_path: natural_index, ordinal: 0, component: pit_hub_field)
349
+ @constellation.IndexField(access_path: natural_index, ordinal: 1, component: date_field)
350
+
351
+ # Add a foreign key to the hub
352
+ fk = @constellation.ForeignKey(
353
+ :new,
354
+ source_composite: pit_composite,
355
+ composite: hub_composite,
356
+ absorption: nil # REVISIT: This is a ForeignKey without its mandatory Absorption. That's gonna hurt
357
+ )
358
+ @constellation.ForeignKeyField(foreign_key: fk, ordinal: 0, component: pit_hub_field)
359
+ # This should be filled in by complete_foreign_keys, but there is no Absorption
360
+ @constellation.IndexField(access_path: fk, ordinal: 0, component: hub_hash_field)
361
+
362
+ # inject hash and load date time for sats associated with all pit members
363
+ pit_members = @pit_members[pit_composite]
364
+ sat_composites = pit_members.map{|pm| @pit_satellite[pm]}.compact.uniq
365
+
366
+ sat_composites.each do |sat_composite|
367
+ sat_name = sat_composite.mapping.name
368
+ sat_hash_name = "#{sat_name}#{@option_id}"
369
+
370
+ src_hash_field = hub_hash_field.fork_to_new_parent(pit_composite.mapping)
371
+ src_hash_field.name = sat_hash_name
372
+ src_load_field = @constellation.ValidFrom(:new,
373
+ parent: pit_composite.mapping,
374
+ name: "#{sat_name} Load"+datestamp_type_name,
375
+ object_type: datestamp_type
376
+ )
377
+
378
+ sat_index_fields = sat_composite.primary_index.all_index_field.to_a
379
+ sat_hash_field = sat_index_fields[0].component
380
+ sat_load_field = sat_index_fields[1].component
381
+
382
+ # Add a foreign key to the satellite's primary key and load date time
383
+ fk = @constellation.ForeignKey(
384
+ :new,
385
+ source_composite: pit_composite,
386
+ composite: sat_composite,
387
+ absorption: nil # REVISIT: This is a ForeignKey without its mandatory Absorption. That's gonna hurt
388
+ )
389
+ @constellation.ForeignKeyField(foreign_key: fk, ordinal: 0, component: src_hash_field)
390
+ @constellation.IndexField(access_path: fk, ordinal: 0, component: sat_hash_field)
391
+ @constellation.ForeignKeyField(foreign_key: fk, ordinal: 1, component: src_load_field)
392
+ @constellation.IndexField(access_path: fk, ordinal: 1, component: sat_load_field)
393
+ end
394
+ pit_composite.mapping.re_rank
183
395
  end
184
396
 
185
397
  def delete_reference_table_foreign_keys
@@ -192,48 +404,10 @@ module ActiveFacts
192
404
  end
193
405
 
194
406
  def prefer_natural_key building_natural_key, source_composite, target_composite
195
- return false if building_natural_key && @link_composites.include?(source_composite)
407
+ return false if building_natural_key && (@link_composites.include?(source_composite) || @bdv_link_composites.include?(source_composite))
196
408
  building_natural_key && @hub_composites.include?(target_composite)
197
409
  end
198
410
 
199
- def composite_key_structure composite
200
- # We know that composite.mapping.object_type is an EntityType because all ValueType composites are reference tables
201
-
202
- object_type = composite.mapping.object_type
203
- mapped_to =
204
- object_type.preferred_identifier.role_sequence.all_role_ref_in_order.map do |role_ref|
205
- player = role_ref.role.object_type
206
- next nil if player == object_type && role_ref.role.fact_type.all_role.size == 1 # Unaries.
207
- candidate = @candidates[player]
208
- next nil unless candidate
209
- # Take care of full absorption
210
- while candidate.full_absorption
211
- candidate = candidate.full_absorption.composition
212
- end
213
- @non_reference_composites.include?(c = candidate.mapping.composite) ? c : nil
214
- end
215
-
216
- trace :datavault, "Preferred identifier for #{composite.mapping.name} encloses foreign keys to #{mapped_to.inspect}" unless mapped_to.compact.empty?
217
-
218
- number_of_keys = mapped_to.compact.size
219
- number_of_values = mapped_to.size-number_of_keys
220
- trace :datavault_classify,
221
- if number_of_keys > 1
222
- # Links have more than one FK to a hub in their key
223
- "Link #{composite.mapping.name} links #{mapped_to.compact.inspect} with #{number_of_values} values"
224
- elsif number_of_keys == 1 && number_of_values > 0
225
- # This is a new hub with a composite key - but we will have to eliminate the foreign key to the base hub
226
- "Augmented Hub #{composite.mapping.name} has a hub link to #{mapped_to.compact[0].inspect} and #{number_of_values} values"
227
- elsif number_of_keys == 1
228
- # This is a new hub with a single-part key that references another hub.
229
- "Dependent Hub #{composite.mapping.name} is identified by another hub: #{mapped_to.compact[0].inspect}"
230
- else
231
- "Hub #{composite.mapping.name} has #{mapped_to.size} parts in its key"
232
- end
233
-
234
- mapped_to
235
- end
236
-
237
411
  # For each member of this composite, decide whether to devolve it to a satellite
238
412
  # or to a new link. If it goes to a link that's still part of this natural key,
239
413
  # we need to leave that key intact, but remove the foreign key it entails.
@@ -273,12 +447,13 @@ module ActiveFacts
273
447
  # We may absorb a subtype that has no contents. There's no point moving these to a satellite.
274
448
  next if is_empty_inheritance member
275
449
 
276
- satellite_name = name_satellite member
277
- satellite = satellites[satellite_name]
278
- unless satellite
279
- satellite =
280
- satellites[satellite_name] =
281
- create_satellite satellite_name, composite
450
+ satellite_name, is_computed = *name_satellite(member)
451
+ if !(satellite = satellites[satellite_name])
452
+ satellite = satellites[satellite_name] = create_satellite(satellite_name, composite)
453
+ satellite.composite_group = (is_computed ? 'bdv' : 'rdv')
454
+ if member.is_a?(MM::Absorption) && check_pit(member)
455
+ @pit_satellite[member] = satellite
456
+ end
282
457
  end
283
458
 
284
459
  devolve_member_to_satellite satellite, member
@@ -332,20 +507,34 @@ module ActiveFacts
332
507
  satellite.classify_constraints
333
508
  satellite.all_local_constraint.map(&:local_constraint).each(&:retract)
334
509
  leaf_constraints = satellite.mapping.all_leaf.flat_map(&:all_leaf_constraint).map(&:leaf_constraint).each(&:retract)
510
+
511
+ if satellite.composite_group == 'bdv'
512
+ @bdv_sat_composites << satellite
513
+ else
514
+ @sat_composites << satellite
515
+ end
335
516
  end
336
517
  end
337
518
 
338
519
  # Decide what to call a new satellite that will adopt this component
339
- def name_satellite component
520
+ def satellite_base_name_and_type component
521
+ computed_name = nil
340
522
  satellite_name =
341
523
  if component.is_a?(MM::Absorption)
342
524
  pc = component.parent_role.base_role.uniqueness_constraint and
343
- pc.concept.all_concept_annotation.map{|ca| ca.mapping_annotation =~ /^satellite *(.*)/ && $1}.compact.uniq[0]
525
+ pc.concept.all_concept_annotation.map do |ca|
526
+ computed_name = ca.mapping_annotation =~ /^computed satellite *(.*)/ && "#{$1} Computed"
527
+ ca.mapping_annotation =~ /^satellite *(.*)/ && $1 or computed_name
528
+ end.compact.uniq[0]
344
529
  # REVISIT: How do we name the satellite for an Indicator? Add a Concept Annotation on the fact type?
345
530
  end
346
531
  satellite_name = satellite_name.words.capcase if satellite_name
347
- satellite_name ||= component.root.mapping.name
348
- satellite_name = apply_name(@option_sat_name, satellite_name)
532
+ [ satellite_name || component.root.mapping.name, computed_name ]
533
+ end
534
+
535
+ def name_satellite component
536
+ name, is_computed = *satellite_base_name_and_type(component)
537
+ [apply_name(@option_sat_name, name), is_computed != nil]
349
538
  end
350
539
 
351
540
  # Create a new satellite for the same object_type as this composite
@@ -502,14 +691,23 @@ module ActiveFacts
502
691
  end
503
692
 
504
693
  def rename_parents
505
- @link_composites.each do |composite|
506
- composite.mapping.name = apply_name(@option_link_name, composite.mapping.name)
694
+ @reference_composites.each do |composite|
695
+ composite.mapping.name = apply_name(@option_ref_name, composite.mapping.name)
507
696
  end
508
697
  @hub_composites.each do |composite|
509
698
  composite.mapping.name = apply_name(@option_hub_name, composite.mapping.name)
510
699
  end
511
- @reference_composites.each do |composite|
512
- composite.mapping.name = apply_name(@option_ref_name, composite.mapping.name)
700
+ @link_composites.each do |composite|
701
+ composite.mapping.name = apply_name(@option_link_name, composite.mapping.name)
702
+ end
703
+ @bdv_link_composites.each do |composite|
704
+ composite.mapping.name = apply_name(@option_link_name, composite.mapping.name)
705
+ end
706
+ @pit_composites.each do |composite|
707
+ composite.mapping.name = apply_name(@option_pit_name, composite.mapping.name)
708
+ end
709
+ @bridge_composites.each do |composite|
710
+ composite.mapping.name = apply_name(@option_bridge_name, composite.mapping.name)
513
711
  end
514
712
  end
515
713