diff --git a/concept/service.go b/concept/service.go index d955feb..43a6c5f 100644 --- a/concept/service.go +++ b/concept/service.go @@ -399,20 +399,39 @@ func (s *AggregateService) getConcordedConcept(ctx context.Context, UUID string, } } - + var primaryOldConcept ontology.OldConcept + var foundPrimary bool if primaryAuthority != "" { canonicalConcept := bucketedConcordances[primaryAuthority][0] - var found bool - var primaryConcept ontology.OldConcept - found, primaryConcept, transactionID, err = s.s3.GetConceptAndTransactionID(ctx, canonicalConcept.UUID) + foundPrimary, primaryOldConcept, transactionID, err = s.s3.GetConceptAndTransactionID(ctx, canonicalConcept.UUID) if err != nil { return ontology.OldConcordedConcept{}, "", err - } else if !found { + } else if !foundPrimary { err = fmt.Errorf("canonical concept %s not found in S3", canonicalConcept.UUID) logger.WithField("UUID", UUID).Error(err.Error()) return ontology.OldConcordedConcept{}, "", err } - oldConcepts = append(oldConcepts, primaryConcept) + } + + // transform concepts to the new format + if primaryOldConcept.UUID == "" { + // there is no primary authority concept + sourceCount := len(oldConcepts) + if sourceCount == 0 { + // sanity check. concordances gathering should return 404 if there are no sources. + // we don't return an error in order to keep the same behavior as in v1.23 of the service. + logger.WithTransactionID(transactionID).WithUUID(UUID).Error("no sources found") + return ontology.OldConcordedConcept{}, "", nil + } + // set the primary concept to the last source concept to keep the behaviour the same as in v1.23 + primaryOldConcept = oldConcepts[sourceCount-1] + oldConcepts = oldConcepts[:sourceCount-1] + } + + primaryConcept, err := primaryOldConcept.ToSourceConcept() + if err != nil { + logger.WithError(err).WithTransactionID(transactionID).WithUUID(primaryOldConcept.UUID).Error("failed to transform primary concept to new format") + return ontology.OldConcordedConcept{}, "", err } var sources []ontology.SourceConcept @@ -424,7 +443,7 @@ func (s *AggregateService) getConcordedConcept(ctx context.Context, UUID string, } sources = append(sources, sourceConcept) } - concordedConcept := ontology.CreateAggregateConcept(sources) + concordedConcept := ontology.CreateAggregateConcept(primaryConcept, sources) oldConcorded, err := concordedConcept.ToOldConcordedConcept() if err != nil { logger.WithError(err).WithTransactionID(transactionID).WithUUID(concordedConcept.PrefUUID).Error("failed to transform concorded concept to old format") diff --git a/ontology/aggregate.go b/ontology/aggregate.go index 4039713..31217e1 100644 --- a/ontology/aggregate.go +++ b/ontology/aggregate.go @@ -9,14 +9,21 @@ const ( ManagedLocationAuthority = "ManagedLocation" ) -func CreateAggregateConcept(sources []SourceConcept) ConcordedConcept { +// CreateAggregateConcept creates ConcordedConcept by merging properties and relationships from primary and others SourceConcept +// When merging the data from the primary SourceConcept takes precedent. +// So if a property is present in both "primary" and one or more "other" SourceConcept, +// the data from the primary will be in the ConcordedConcept +// Exception to this rule are relationships that are with MergingStrategy: AggregateStrategy. +// Those relationships will be collected from both primary and others SourceConcept into ConcordedConcept +func CreateAggregateConcept(primary SourceConcept, others []SourceConcept) ConcordedConcept { var scopeNoteOptions = map[string][]string{} concordedConcept := ConcordedConcept{} concordedConcept.Fields = map[string]interface{}{} // initialise Fields to be able to safely access it later - for _, src := range sources { + for _, src := range others { concordedConcept = mergeCanonicalInformation(concordedConcept, src, scopeNoteOptions) } + concordedConcept = mergeCanonicalInformation(concordedConcept, primary, scopeNoteOptions) concordedConcept.Aliases = deduplicateAndSkipEmptyAliases(concordedConcept.Aliases) concordedConcept.ScopeNote = chooseScopeNote(concordedConcept, scopeNoteOptions) return concordedConcept diff --git a/ontology/aggregate_test.go b/ontology/aggregate_test.go index 762aa8f..1bc932a 100644 --- a/ontology/aggregate_test.go +++ b/ontology/aggregate_test.go @@ -25,7 +25,8 @@ func TestCreateAggregateConcept(t *testing.T) { t.Run(name, func(t *testing.T) { sources := readSourcesFixture(t, test.Sources) expected := readAggregateFixture(t, test.Aggregate) - actual := CreateAggregateConcept(sources) + primary := sources[len(sources)-1] + actual := CreateAggregateConcept(primary, sources[:len(sources)-1]) sortAliases(&expected) sortAliases(&actual) if !cmp.Equal(expected, actual) { @@ -68,7 +69,8 @@ func TestCreateAggregateConcept_WithDummyConfig(t *testing.T) { sources := readSourcesFixture(t, test.Sources) expected := readAggregateFixture(t, test.Aggregate) - actual := CreateAggregateConcept(sources) + primary := sources[len(sources)-1] + actual := CreateAggregateConcept(primary, sources[:len(sources)-1]) sortAliases(&expected) sortAliases(&actual) if !cmp.Equal(expected, actual) {