internal CdmE2ERelationship LocalizeRelToManifest(CdmE2ERelationship rel) { CdmE2ERelationship relCopy = this.Ctx.Corpus.MakeObject <CdmE2ERelationship>(CdmObjectType.E2ERelationshipDef, rel.Name); relCopy.ToEntity = this.Ctx.Corpus.Storage.CreateRelativeCorpusPath(rel.ToEntity, this); relCopy.FromEntity = this.Ctx.Corpus.Storage.CreateRelativeCorpusPath(rel.FromEntity, this); relCopy.ToEntityAttribute = rel.ToEntityAttribute; relCopy.FromEntityAttribute = rel.FromEntityAttribute; relCopy.ExhibitsTraits.AddRange(rel.ExhibitsTraits); return(relCopy); }
public override CdmObject Copy(ResolveOptions resOpt = null) { if (resOpt == null) { resOpt = new ResolveOptions(this); } var copy = new CdmE2ERelationship(this.Ctx, this.GetName()) { FromEntity = this.FromEntity, FromEntityAttribute = this.FromEntityAttribute, ToEntity = this.ToEntity, ToEntityAttribute = this.ToEntityAttribute }; this.CopyDef(resOpt, copy); return(copy); }
/// <summary> /// finds any relative corpus paths that are held within this document and makes them relative to the new folder instead /// </summary> internal bool LocalizeCorpusPaths(CdmFolderDefinition newFolder) { bool allWentWell = true; bool wasBlocking = this.Ctx.Corpus.blockDeclaredPathChanges; this.Ctx.Corpus.blockDeclaredPathChanges = true; // shout into the void Logger.Info(nameof(CdmDocumentDefinition), (ResolveContext)this.Ctx, $"Localizing corpus paths in document '{this.Name}'", nameof(LocalizeCorpusPaths)); // find anything in the document that is a corpus path this.Visit("", new VisitCallback { Invoke = (iObject, path) => { // i don't like that document needs to know a little about these objects // in theory, we could create a virtual function on cdmObject that localizes properties // but then every object would need to know about the documents and paths and such ... // also, i already wrote this code. switch (iObject.ObjectType) { case CdmObjectType.Import: { CdmImport typeObj = iObject as CdmImport; typeObj.CorpusPath = LocalizeCorpusPath(typeObj.CorpusPath, newFolder, ref allWentWell) ?? typeObj.CorpusPath; break; } case CdmObjectType.LocalEntityDeclarationDef: case CdmObjectType.ReferencedEntityDeclarationDef: { CdmEntityDeclarationDefinition typeObj = iObject as CdmEntityDeclarationDefinition; typeObj.EntityPath = LocalizeCorpusPath(typeObj.EntityPath, newFolder, ref allWentWell) ?? typeObj.EntityPath; break; } case CdmObjectType.DataPartitionDef: { CdmDataPartitionDefinition typeObj = iObject as CdmDataPartitionDefinition; typeObj.Location = LocalizeCorpusPath(typeObj.Location, newFolder, ref allWentWell) ?? typeObj.Location; typeObj.SpecializedSchema = LocalizeCorpusPath(typeObj.SpecializedSchema, newFolder, ref allWentWell) ?? typeObj.SpecializedSchema; break; } case CdmObjectType.DataPartitionPatternDef: { CdmDataPartitionPatternDefinition typeObj = iObject as CdmDataPartitionPatternDefinition; typeObj.RootLocation = LocalizeCorpusPath(typeObj.RootLocation, newFolder, ref allWentWell) ?? typeObj.RootLocation; typeObj.SpecializedSchema = LocalizeCorpusPath(typeObj.SpecializedSchema, newFolder, ref allWentWell) ?? typeObj.SpecializedSchema; break; } case CdmObjectType.E2ERelationshipDef: { CdmE2ERelationship typeObj = iObject as CdmE2ERelationship; typeObj.ToEntity = LocalizeCorpusPath(typeObj.ToEntity, newFolder, ref allWentWell) ?? typeObj.ToEntity; typeObj.FromEntity = LocalizeCorpusPath(typeObj.FromEntity, newFolder, ref allWentWell) ?? typeObj.FromEntity; break; } case CdmObjectType.ManifestDeclarationDef: { CdmManifestDeclarationDefinition typeObj = iObject as CdmManifestDeclarationDefinition; typeObj.Definition = LocalizeCorpusPath(typeObj.Definition, newFolder, ref allWentWell) ?? typeObj.Definition; break; } } return(false); } }, null); this.Ctx.Corpus.blockDeclaredPathChanges = wasBlocking; return(allWentWell); }
/// <summary> /// Populates the relationships that the entities in the current manifest are involved in. /// </summary> public async Task PopulateManifestRelationshipsAsync(CdmRelationshipDiscoveryStyle option = CdmRelationshipDiscoveryStyle.All) { using (Logger.EnterScope(nameof(CdmManifestDefinition), Ctx, nameof(PopulateManifestRelationshipsAsync))) { this.Relationships.Clear(); HashSet <string> relCache = new HashSet <string>(); if (this.Entities != null) { foreach (CdmEntityDeclarationDefinition entDec in this.Entities) { string entPath = await this.GetEntityPathFromDeclaration(entDec, this); CdmEntityDefinition currEntity = await this.Ctx.Corpus.FetchObjectAsync <CdmEntityDefinition>(entPath); if (currEntity == null) { continue; } // handle the outgoing relationships List <CdmE2ERelationship> outgoingRels = this.Ctx.Corpus.FetchOutgoingRelationships(currEntity); if (outgoingRels != null) { foreach (CdmE2ERelationship rel in outgoingRels) { string cacheKey = rel2CacheKey(rel); if (!relCache.Contains(cacheKey) && this.IsRelAllowed(rel, option)) { this.Relationships.Add(this.LocalizeRelToManifest(rel)); relCache.Add(cacheKey); } } } List <CdmE2ERelationship> incomingRels = this.Ctx.Corpus.FetchIncomingRelationships(currEntity); if (incomingRels != null) { foreach (CdmE2ERelationship inRel in incomingRels) { // get entity object for current toEntity CdmEntityDefinition currentInBase = await this.Ctx.Corpus.FetchObjectAsync <CdmEntityDefinition>(inRel.ToEntity, this); if (currentInBase == null) { continue; } // create graph of inheritance for to currentInBase // graph represented by an array where entity at i extends entity at i+1 List <CdmEntityDefinition> toInheritanceGraph = new List <CdmEntityDefinition>(); while (currentInBase != null) { var resOpt = new ResolveOptions { WrtDoc = currentInBase.InDocument }; currentInBase = currentInBase.ExtendsEntity?.FetchObjectDefinition <CdmEntityDefinition>(resOpt); if (currentInBase != null) { toInheritanceGraph.Add(currentInBase); } } // add current incoming relationship string cacheKey = rel2CacheKey(inRel); if (!relCache.Contains(cacheKey) && this.IsRelAllowed(inRel, option)) { this.Relationships.Add(this.LocalizeRelToManifest(inRel)); relCache.Add(cacheKey); } // if A points at B, A's base classes must point at B as well foreach (CdmEntityDefinition baseEntity in toInheritanceGraph) { List <CdmE2ERelationship> incomingRelsForBase = this.Ctx.Corpus.FetchIncomingRelationships(baseEntity); if (incomingRelsForBase != null) { foreach (CdmE2ERelationship inRelBase in incomingRelsForBase) { CdmE2ERelationship newRel = new CdmE2ERelationship(this.Ctx, "") { FromEntity = inRelBase.FromEntity, FromEntityAttribute = inRelBase.FromEntityAttribute, ToEntity = inRel.ToEntity, ToEntityAttribute = inRel.ToEntityAttribute }; string baseRelCacheKey = rel2CacheKey(newRel); if (!relCache.Contains(baseRelCacheKey) && this.IsRelAllowed(newRel, option)) { this.Relationships.Add(this.LocalizeRelToManifest(newRel)); relCache.Add(baseRelCacheKey); } } } } } } } if (this.SubManifests != null) { foreach (CdmManifestDeclarationDefinition subManifestDef in this.SubManifests) { var corpusPath = this.Ctx.Corpus.Storage.CreateAbsoluteCorpusPath(subManifestDef.Definition, this); var subManifest = await this.Ctx.Corpus.FetchObjectAsync <CdmManifestDefinition>(corpusPath); await subManifest.PopulateManifestRelationshipsAsync(option); } } } } }
// Standardized way of turning a relationship object into a key for caching // without using the object itself as a key (could be duplicate relationship objects). internal string rel2CacheKey(CdmE2ERelationship rel) { return($"{rel.ToEntity}|{rel.ToEntityAttribute}|{rel.FromEntity}|{rel.FromEntityAttribute}"); }