/// <summary> /// Create a relationship linking by creating an entity attribute definition instance with a trait. /// This allows you to add a resolution guidance to customize your data. /// </summary> /// <param name="cdmCorpus"> The CDM corpus. </param> /// <param name="associatedEntityName"> The name of the associated entity. </param> /// <param name="foreignKeyName"> The name of the foreign key. </param> /// <param name="attributeExplanation"> The explanation of the attribute.</param> /// <returns> The instance of entity attribute definition. </returns> private static CdmEntityAttributeDefinition CreateEntityAttributeForRelationshipBetweenTwoEntities( CdmCorpusDefinition cdmCorpus, string associatedEntityName, string foreignKeyName, string attributeExplanation) { // Define a relationship by creating an entity attribute var entityAttributeDef = cdmCorpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, foreignKeyName); entityAttributeDef.Explanation = attributeExplanation; // Creating an entity reference for the associated entity CdmEntityReference associatedEntityRef = cdmCorpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, associatedEntityName, false); // Creating a "is.identifiedBy" trait for entity reference CdmTraitReference traitReference = cdmCorpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, "is.identifiedBy", false); traitReference.Arguments.Add(null, $"{associatedEntityName}/(resolvedAttributes)/{associatedEntityName}Id"); // Add the trait to the attribute's entity reference associatedEntityRef.AppliedTraits.Add(traitReference); entityAttributeDef.Entity = associatedEntityRef; entityAttributeDef.Purpose = CreateRelationshipMeanings(cdmCorpus, "Non-simple resolution guidance sample"); // Add resolution guidance var attributeResolution = cdmCorpus.MakeObject <CdmAttributeResolutionGuidance>(CdmObjectType.AttributeResolutionGuidanceDef); attributeResolution.entityByReference = attributeResolution.makeEntityByReference(); attributeResolution.entityByReference.allowReference = true; attributeResolution.renameFormat = "{m}"; var entityAttribute = CreateTypeAttributeWithPurposeAndDataType(cdmCorpus, $"{foreignKeyName}Id", "identifiedBy", "entityId"); attributeResolution.entityByReference.foreignKeyAttribute = entityAttribute as CdmTypeAttributeDefinition; entityAttributeDef.ResolutionGuidance = attributeResolution; return(entityAttributeDef); }
public async Task TestNestedProjUsingObjectModel() { CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(testsSubpath, "TestNestedProjUsingObjectModel"); corpus.Storage.Mount("local", new LocalAdapter(TestHelper.GetActualOutputFolderPath(testsSubpath, "TestNestedProjUsingObjectModel"))); CdmFolderDefinition localRoot = corpus.Storage.FetchRootFolder("local"); // Create an entity CdmEntityDefinition entity = ProjectionTestUtils.CreateEntity(corpus, localRoot); // Create a projection CdmProjection projection = ProjectionTestUtils.CreateProjection(corpus, localRoot); // Create an ExcludeAttributes operation CdmOperationExcludeAttributes excludeAttrsOp = corpus.MakeObject <CdmOperationExcludeAttributes>(CdmObjectType.OperationExcludeAttributesDef); excludeAttrsOp.ExcludeAttributes.Add("id"); excludeAttrsOp.ExcludeAttributes.Add("date"); projection.Operations.Add(excludeAttrsOp); // Create an entity reference to hold this projection CdmEntityReference projectionEntityRef = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef.ExplicitReference = projection; // Create another projection that uses the previous projection as its source CdmProjection projection2 = corpus.MakeObject <CdmProjection>(CdmObjectType.ProjectionDef); projection2.Source = projectionEntityRef; // Create an ExcludeAttributes operation CdmOperationExcludeAttributes excludeAttrsOp2 = corpus.MakeObject <CdmOperationExcludeAttributes>(CdmObjectType.OperationExcludeAttributesDef); excludeAttrsOp2.ExcludeAttributes.Add("value"); projection2.Operations.Add(excludeAttrsOp2); // Create an entity reference to hold this projection CdmEntityReference projectionEntityRef2 = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef2.ExplicitReference = projection2; // Create an entity attribute that contains this projection and add this to the entity CdmEntityAttributeDefinition entityAttribute = corpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, "TestEntityAttribute"); entityAttribute.Entity = projectionEntityRef2; entity.Attributes.Add(entityAttribute); // Resolve the entity CdmEntityDefinition resolvedEntity = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", null, localRoot); // Verify correctness of the resolved attributes after running the ExcludeAttributes operations // Original set of attributes: ["id", "name", "value", "date"] // Excluded attributes: ["id", "date"], ["value"] Assert.AreEqual(1, resolvedEntity.Attributes.Count); Assert.AreEqual("name", (resolvedEntity.Attributes[0] as CdmTypeAttributeDefinition).Name); }
/// <summary> /// Create a relationship linking with an attribute an entity attribute definition instance without a trait. /// </summary> /// <param name="cdmCorpus"> The CDM corpus. </param> /// <param name="associatedEntityName"> The name of . </param> /// <param name="foreignKeyName"> The name of the foreign key. </param> /// <param name="attributeExplanation"> The explanation of the attribute.</param> /// <returns> The instance of entity attribute definition. </returns> private static CdmEntityAttributeDefinition CreateSimpleEntityAttributeForRelationshipBetweenTwoEntities( CdmCorpusDefinition cdmCorpus, string associatedEntityName, string foreignKeyName, string attributeExplanation) { // Define a relationship by creating an entity attribute var entityAttributeDef = cdmCorpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, foreignKeyName); entityAttributeDef.Explanation = attributeExplanation; // Creating an entity reference for the associated entity - simple name reference entityAttributeDef.Entity = cdmCorpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, associatedEntityName, true); entityAttributeDef.Purpose = CreateRelationshipMeanings(cdmCorpus, "Simple resolution guidance sample"); // Add resolution guidance - enable reference var attributeResolution = cdmCorpus.MakeObject <CdmAttributeResolutionGuidance>(CdmObjectType.AttributeResolutionGuidanceDef); attributeResolution.entityByReference = attributeResolution.makeEntityByReference(); attributeResolution.entityByReference.allowReference = true; entityAttributeDef.ResolutionGuidance = attributeResolution; return(entityAttributeDef); }
/// <summary> /// Create an entity 'TestEntityNestedProjection' that extends from a projection /// </summary> /// <param name="corpus"></param> /// <param name="manifestDefault"></param> /// <param name="localRoot"></param> /// <returns></returns> private CdmEntityDefinition CreateEntityTestEntityNestedProjection(CdmCorpusDefinition corpus, CdmManifestDefinition manifestDefault, CdmFolderDefinition localRoot) { string entityName = "TestEntityNestedProjection"; CdmEntityReference inlineProjectionEntityRef = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); inlineProjectionEntityRef.ExplicitReference = CreateNestedProjection(corpus); CdmEntityDefinition entityTestEntityNestedProjection = corpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, entityName); entityTestEntityNestedProjection.ExtendsEntity = inlineProjectionEntityRef; CdmDocumentDefinition entityTestEntityNestedProjectionDoc = corpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{entityName}.cdm.json", false); entityTestEntityNestedProjectionDoc.Imports.Add(FoundationJsonPath); entityTestEntityNestedProjectionDoc.Imports.Add("TestSource.cdm.json"); entityTestEntityNestedProjectionDoc.Definitions.Add(entityTestEntityNestedProjection); localRoot.Documents.Add(entityTestEntityNestedProjectionDoc, entityTestEntityNestedProjectionDoc.Name); manifestDefault.Entities.Add(entityTestEntityNestedProjection); return(entityTestEntityNestedProjection); }
public void Process(TraitAnnotation annotation) { string traitName = annotation.Value; CdmTraitReference trait = corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, traitName, false); foreach (var argument in annotation.Arguments) { if (argument.Value != null) { trait.Arguments.Add(argument.Key, argument.Value); } } attribute.AppliedTraits.Add(trait); }
public async Task TestMissingPersistenceFormat() { var expectedLogCodes = new HashSet <CdmLogCode> { CdmLogCode.ErrPersistClassMissing }; CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(testsSubpath, "TestMissingPersistenceFormat", expectedCodes: expectedLogCodes); CdmFolderDefinition folder = corpus.Storage.FetchRootFolder(corpus.Storage.DefaultNamespace); CdmManifestDefinition manifest = corpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "someManifest"); folder.Documents.Add(manifest); // trying to save to an unsupported format should return false and not fail bool succeded = await manifest.SaveAsAsync("manifest.unSupportedExtension"); Assert.IsFalse(succeded); }
private static async Task SaveCDMDocuments(string nameSpace, CdmCorpusDefinition cdmCorpus) { Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local documents in the corpus. var localRoot = cdmCorpus.Storage.FetchRootFolder(nameSpace); localRoot.Documents.Add(manifestAbstract); // Create two entities from scratch, and add some attributes, traits, properties, and relationships in between Console.WriteLine("Create net new entities"); DTDLParser parser = new DTDLParser(dtdlRoot, "json"); foreach (DTInterfaceInfo info in parser.DTDLInterfaces) { CreateCustomEntity(cdmCorpus, manifestAbstract, localRoot, info); } // Create the resolved version of everything in the root folder too Console.WriteLine("Resolve the placeholder"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestResolved.Imports.Add("cdm:/foundations.cdm.json"); Console.WriteLine($"Save the folders and partition data documents to {nameSpace} storage."); await SavePartitionDocuments(nameSpace, cdmCorpus, manifestResolved); Console.WriteLine($"Save the manifest, entity and resolved documents to {nameSpace} storage."); // Save all other files (resolved, manifest, entity etc.) var manifestFileName = $"{manifestResolved.ManifestName}.manifest.cdm.json"; var manifestSaved = await manifestResolved.SaveAsAsync(manifestFileName, true); LogSaveOutput(manifestSaved, manifestFileName); var modelFileName = "model.json"; var modelSaved = await manifestResolved.SaveAsAsync(modelFileName, true); LogSaveOutput(modelSaved, modelFileName); }
public async Task <List <string> > InitializeCdmFolderAsync(IEnumerable <TabularMappingDefinition> tabularMappings, string rootFolder = "local") { _cdmCorpusDefinition.SetEventCallback(null, CdmStatusLevel.None); CdmManifestDefinition manifestAbstract = _cdmCorpusDefinition.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); var localRoot = _cdmCorpusDefinition.Storage.FetchRootFolder(rootFolder); localRoot.Documents.Add(manifestAbstract); List <string> entities = await BuildCdmEntitys(_cdmCorpusDefinition, manifestAbstract, localRoot, tabularMappings); CdmManifestDefinition manifestResolved = await CreateResolvedManifest(manifestAbstract); await CreateDataPatitions(_cdmCorpusDefinition, manifestResolved); await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); return(entities); }
private async static Task <CdmManifestDefinition> LoadAndResolveManifest(CdmCorpusDefinition corpus, CdmManifestDefinition manifest, string renameSuffix) { Console.WriteLine("Resolving manifest " + manifest.ManifestName + " ..."); CdmManifestDefinition resolvedManifest = await manifest.CreateResolvedManifestAsync(manifest.ManifestName + renameSuffix, "{n}-resolved.cdm.json"); foreach (CdmManifestDeclarationDefinition subManifestDecl in manifest.SubManifests) { CdmManifestDefinition subManifest = await corpus.FetchObjectAsync <CdmManifestDefinition>(subManifestDecl.Definition, manifest); CdmManifestDefinition resolvedSubManifest = await LoadAndResolveManifest(corpus, subManifest, renameSuffix); CdmManifestDeclarationDefinition resolvedDecl = corpus.MakeObject <CdmManifestDeclarationDefinition>(CdmObjectType.ManifestDeclarationDef, resolvedSubManifest.ManifestName); resolvedDecl.Definition = corpus.Storage.CreateRelativeCorpusPath(resolvedSubManifest.AtCorpusPath, resolvedManifest); resolvedManifest.SubManifests.Add(resolvedDecl); } return(resolvedManifest); }
public IEnumerable <CdmE2ERelationship> GenerateRelationships(Table table) { var fkColumns = table.Columns.Where(t => t.IsForeignKey); foreach (var column in fkColumns) { var relationshipName = $"relationship-{table.Name}-{column.Name}"; var relationship = corpus.MakeObject <CdmE2ERelationship>(CdmObjectType.E2ERelationshipDef, relationshipName); string fromDocumentName = resolver.GetDocumentFileName(table.Name); relationship.FromEntity = $"{fromDocumentName}/{table.Name}"; relationship.FromEntityAttribute = column.Name; string toDocumentName = resolver.GetDocumentFileName(column.ForeignKey.Table.Name); relationship.ToEntity = $"{toDocumentName}/{column.ForeignKey.Table.Name}"; relationship.ToEntityAttribute = column.ForeignKey.Name; yield return(relationship); } }
public void TestCdmCollectionAddingList() { var cdmCorpus = new CdmCorpusDefinition(); cdmCorpus.Storage.DefaultNamespace = "local"; cdmCorpus.Storage.Mount("local", new LocalAdapter("CdmCorpus/LocalPath")); var ctx = cdmCorpus.Ctx; var cdmDocument = new CdmDocumentDefinition(ctx, "NameOfDocument"); var collection = new CdmCollection <CdmEntityDeclarationDefinition>(ctx, cdmDocument, Enums.CdmObjectType.LocalEntityDeclarationDef); var entityList = new List <CdmEntityDeclarationDefinition>(); for (int i = 0; i < 2; i++) { var entity = new CdmEntityDefinition(cdmCorpus.Ctx, $"entityName_{i}", null); CdmCollectionHelperFunctions.CreateDocumentForEntity(cdmCorpus, entity); var entityDeclaration = cdmCorpus.MakeObject <CdmEntityDeclarationDefinition>(Enums.CdmObjectType.LocalEntityDeclarationDef, entity.EntityName, false); entityDeclaration.Owner = entity.Owner; entityDeclaration.EntityPath = $"{entity.Owner.AtCorpusPath}/{entity.EntityName}"; entityList.Add(entityDeclaration); } Assert.AreEqual(0, collection.Count); collection.AddRange(entityList); Assert.AreEqual(2, collection.Count); for (int i = 0; i < 2; i++) { Assert.AreEqual($"entityName_{i}", collection[i].EntityName); } }
/// <summary> /// Creates a source entity for a projection /// </summary> public static CdmEntityDefinition CreateSourceEntity(CdmCorpusDefinition corpus, CdmFolderDefinition localRoot) { string entityName = "SourceEntity"; CdmEntityDefinition entity = corpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, entityName); string attributeName1 = "id"; CdmTypeAttributeDefinition attribute1 = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, attributeName1); attribute1.DataType = corpus.MakeRef <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "string", true); entity.Attributes.Add(attribute1); string attributeName2 = "name"; CdmTypeAttributeDefinition attribute2 = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, attributeName2); attribute2.DataType = corpus.MakeRef <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "string", true); entity.Attributes.Add(attribute2); string attributeName3 = "value"; CdmTypeAttributeDefinition attribute3 = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, attributeName3); attribute3.DataType = corpus.MakeRef <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "integer", true); entity.Attributes.Add(attribute3); string attributeName4 = "date"; CdmTypeAttributeDefinition attribute4 = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, attributeName4); attribute4.DataType = corpus.MakeRef <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "date", true); entity.Attributes.Add(attribute4); CdmDocumentDefinition entityDoc = corpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{entityName}.cdm.json", false); entityDoc.Imports.Add(foundationJsonPath); entityDoc.Definitions.Add(entity); localRoot.Documents.Add(entityDoc, entityDoc.Name); return(entity); }
public async Task TestEntityAttributeProjUsingObjectModel() { CdmCorpusDefinition corpus = ProjectionTestUtils.GetLocalCorpus(testsSubpath, "TestEntityAttributeProjUsingObjectModel"); corpus.Storage.Mount("local", new LocalAdapter(TestHelper.GetActualOutputFolderPath(testsSubpath, "TestEntityAttributeProjUsingObjectModel"))); CdmFolderDefinition localRoot = corpus.Storage.FetchRootFolder("local"); // Create an entity CdmEntityDefinition entity = ProjectionTestUtils.CreateEntity(corpus, localRoot); // Create a projection CdmProjection projection = ProjectionTestUtils.CreateProjection(corpus, localRoot); // Create an ArrayExpansion operation CdmOperationArrayExpansion arrayExpansionOp = corpus.MakeObject <CdmOperationArrayExpansion>(CdmObjectType.OperationArrayExpansionDef); arrayExpansionOp.StartOrdinal = 1; arrayExpansionOp.EndOrdinal = 2; projection.Operations.Add(arrayExpansionOp); // Create an entity reference to hold this projection CdmEntityReference projectionEntityRef = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef.ExplicitReference = projection; // Create another projection that does a rename so that we can see the expanded attributes in the final resolved entity CdmProjection projection2 = corpus.MakeObject <CdmProjection>(CdmObjectType.ProjectionDef); projection2.Source = projectionEntityRef; // Create a RenameAttributes operation CdmOperationRenameAttributes renameAttrsOp = corpus.MakeObject <CdmOperationRenameAttributes>(CdmObjectType.OperationRenameAttributesDef); renameAttrsOp.RenameFormat = "{m}{o}"; projection2.Operations.Add(renameAttrsOp); // Create an entity reference to hold this projection CdmEntityReference projectionEntityRef2 = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef2.ExplicitReference = projection2; // Create an entity attribute that contains this projection and add this to the entity CdmEntityAttributeDefinition entityAttribute = corpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, "TestEntityAttribute"); entityAttribute.Entity = projectionEntityRef2; entity.Attributes.Add(entityAttribute); // Resolve the entity CdmEntityDefinition resolvedEntity = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", null, localRoot); // Verify correctness of the resolved attributes after running the projections // Original set of attributes: ["id", "name", "value", "date"] // Expand 1...2, renameFormat = {m}{o} Assert.AreEqual(8, resolvedEntity.Attributes.Count); Assert.AreEqual("id1", (resolvedEntity.Attributes[0] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("name1", (resolvedEntity.Attributes[1] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("value1", (resolvedEntity.Attributes[2] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("date1", (resolvedEntity.Attributes[3] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("id2", (resolvedEntity.Attributes[4] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("name2", (resolvedEntity.Attributes[5] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("value2", (resolvedEntity.Attributes[6] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("date2", (resolvedEntity.Attributes[7] as CdmTypeAttributeDefinition).Name); }
static async Task Main() { // Make a corpus, the corpus is the collection of all documents and folders created or discovered while navigating objects and paths var cdmCorpus = new CdmCorpusDefinition(); Console.WriteLine("configure storage adapters"); // Configure storage adapters to point at the target local manifest location and at the fake public standards var pathFromExeToExampleRoot = "../../../../../../"; cdmCorpus.Storage.Mount("local", new LocalAdapter(pathFromExeToExampleRoot + "6-create-net-new-entities")); cdmCorpus.Storage.DefaultNamespace = "local"; // local is our default. so any paths that start out navigating without a device tag will assume local // Fake cdm, normaly use the github adapter // Mount it as the 'cdm' device, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "example-public-standards")); // Example how to mount to the ADLS. // cdmCorpus.Storage.Mount("adls", // new ADLSAdapter( // "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. // "/<FILESYSTEM-NAME>", // Root. // "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. // "<CLIENT-ID>", // Client ID. // "<CLIENT-SECRET>" // Client secret. // )); Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local documents in the corpus var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract, "TempAbstract.manifest.cdm.json"); // Create two entities from scratch, and add some attributes, traits, properties, and relationships in between Console.WriteLine("Create net new entities"); // Create the simplest entity - CustomPerson // Create the entity definition instance var personEntity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, CustomPersonEntityName, false); // Add type attributes to the entity instance var personAttributeId = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomPersonEntityName}Id", "identifiedBy", "entityId"); personEntity.Attributes.Add(personAttributeId); var personAttributeName = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomPersonEntityName}Name", "hasA", "string"); personEntity.Attributes.Add(personAttributeName); // Add properties to the entity instance personEntity.DisplayName = CustomPersonEntityName; personEntity.Version = "0.0.1"; personEntity.Description = "This is a custom entity created for the sample."; // Create the document which contains the entity var personEntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{CustomPersonEntityName}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely personEntityDoc.Imports.Add(FoundationJsonPath); personEntityDoc.Definitions.Add(personEntity); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(personEntityDoc, personEntityDoc.Name); // Add the entity to the manifest manifestAbstract.Entities.Add(personEntity); // Create an entity - CustomAccount which has a relationship with the entity CustomPerson // Create the entity definition instance var accountEntity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, CustomAccountEntityName, false); // Add type attributes to the entity instance var accountAttributeId = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomAccountEntityName}Id", "identifiedBy", "entityId"); accountEntity.Attributes.Add(accountAttributeId); var accountAttributeName = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomAccountEntityName}Name", "hasA", "string"); accountEntity.Attributes.Add(accountAttributeName); // Add properties to the entity instance accountEntity.DisplayName = CustomAccountEntityName; accountEntity.Version = "0.0.1"; accountEntity.Description = "This is a custom entity created for the sample."; // In this sample, every account has one person who owns the account // the relationship is actually an entity attribute var attributeExplanation = "The owner of the account, which is a person."; // You can all CreateSimpleAttributeForRelationshipBetweenTwoEntities() instead, but CreateAttributeForRelationshipBetweenTwoEntities() can show // more details of how to use resolution guidance to customize your data var accountOwnerAttribute = CreateAttributeForRelationshipBetweenTwoEntities(cdmCorpus, CustomPersonEntityName, "accountOwner", attributeExplanation); accountEntity.Attributes.Add(accountOwnerAttribute); // Create the document which contains the entity var accountEntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{CustomAccountEntityName}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely accountEntityDoc.Imports.Add(FoundationJsonPath); // the CustomAccount entity has a relationship with the CustomPerson entity, this relationship is defined from its attribute with traits, // the import to the entity reference CustomPerson's doc is required accountEntityDoc.Imports.Add($"{CustomPersonEntityName}.cdm.json"); accountEntityDoc.Definitions.Add(accountEntity); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(accountEntityDoc, accountEntityDoc.Name); // Add the entity to the manifest manifestAbstract.Entities.Add(accountEntity); // Create an entity which extends "Account" from the standard, it contains everything that "Account" has var extendedStandardAccountEntity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, ExtendedStandardAccount, false); // This function with 'true' will make a simple reference to the base extendedStandardAccountEntity.ExtendsEntity = cdmCorpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, "Account", true); var attrExplanation = "This is a simple custom account for this sample."; // Add a relationship from it to the CustomAccount entity, and name the foreign key to SimpleCustomAccount // You can all CreateSimpleAttributeForRelationshipBetweenTwoEntities() instead, but CreateAttributeForRelationshipBetweenTwoEntities() can show // more details of how to use resolution guidance to customize your data var simpleCustomAccountAttribute = CreateAttributeForRelationshipBetweenTwoEntities(cdmCorpus, CustomAccountEntityName, "SimpleCustomAccount", attrExplanation); extendedStandardAccountEntity.Attributes.Add(simpleCustomAccountAttribute); var extendedStandardAccountntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{ExtendedStandardAccount}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely extendedStandardAccountntityDoc.Imports.Add(FoundationJsonPath); // The ExtendedAccount entity extends from the "Account" entity from standards, the import to the entity Account's doc is required // it also has a relationship with the CustomAccount entity, the relationship defined from its from its attribute with traits, the import to the entity reference CustomAccount's doc is required extendedStandardAccountntityDoc.Imports.Add($"{SchemaDocsRoot}/Account.cdm.json"); extendedStandardAccountntityDoc.Imports.Add($"{CustomAccountEntityName}.cdm.json"); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(extendedStandardAccountntityDoc, extendedStandardAccountntityDoc.Name); extendedStandardAccountntityDoc.Definitions.Add(extendedStandardAccountEntity); // Add the entity to the manifest manifestAbstract.Entities.Add(extendedStandardAccountEntity); // Create the resolved version of everything in the root folder too Console.WriteLine("Resolve the placeholder"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); Console.WriteLine("Save the docs"); foreach (CdmEntityDeclarationDefinition eDef in manifestResolved.Entities) { // Get the entity being pointed at var localEDef = eDef; var entDef = await cdmCorpus.FetchObjectAsync <CdmEntityDefinition>(localEDef.EntityPath, manifestResolved); // Make a fake partition, just to demo that var part = cdmCorpus.MakeObject <CdmDataPartitionDefinition>(CdmObjectType.DataPartitionDef, $"{entDef.EntityName}-data-description"); localEDef.DataPartitions.Add(part); part.Explanation = "not real data, just for demo"; // We have existing partition files for the custom entities, so we need to make the partition point to the file location part.Location = $"local:/{entDef.EntityName}/partition-data.csv"; // Add trait to partition for csv params var csvTrait = part.ExhibitsTraits.Add("is.partition.format.CSV", false); csvTrait.Arguments.Add("columnHeaders", "true"); csvTrait.Arguments.Add("delimiter", ","); } // We can save the docs as manifest.cdm.json format or model.json // Save as manifest.cdm.json await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); // Save as a model.json // await manifestResolved.SaveAsAsync("model.json", true); }
static async Task Main(string[] args) { // Make a corpus, the corpus is the collection of all documents and folders created or discovered while navigating objects and paths var cdmCorpus = new CdmCorpusDefinition(); Console.WriteLine("Configure storage adapters"); // Configure storage adapters to point at the target local manifest location and at the fake public standards string pathFromExeToExampleRoot = "../../../../../../"; cdmCorpus.Storage.Mount("local", new LocalAdapter(pathFromExeToExampleRoot + "2-create-manifest")); cdmCorpus.Storage.DefaultNamespace = "local"; // local is our default. so any paths that start out navigating without a device tag will assume local // Fake cdm, normaly use the github adapter // Mount it as the 'cdm' device, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "example-public-standards")); // Example how to mount to the ADLS. // cdmCorpus.Storage.Mount("adls", // new ADLSAdapter( // "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. // "/<FILESYSTEM-NAME>", // Root. // "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. // "<CLIENT-ID>", // Client ID. // "<CLIENT-SECRET>" // Client secret. // )); Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add each declaration, this example is about medical appointments and care plans manifestAbstract.Entities.Add("Account", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Account.cdm.json/Account"); manifestAbstract.Entities.Add("Address", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Address.cdm.json/Address"); manifestAbstract.Entities.Add("CarePlan", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/CarePlan.cdm.json/CarePlan"); manifestAbstract.Entities.Add("CodeableConcept", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/CodeableConcept.cdm.json/CodeableConcept"); manifestAbstract.Entities.Add("Contact", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Contact.cdm.json/Contact"); manifestAbstract.Entities.Add("Device", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Device.cdm.json/Device"); manifestAbstract.Entities.Add("EmrAppointment", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/EmrAppointment.cdm.json/EmrAppointment"); manifestAbstract.Entities.Add("Encounter", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Encounter.cdm.json/Encounter"); manifestAbstract.Entities.Add("EpisodeOfCare", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/EpisodeOfCare.cdm.json/EpisodeOfCare"); manifestAbstract.Entities.Add("Location", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Location.cdm.json/Location"); // Add the temp manifest to the root of the local documents in the corpus. var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract); // Create the resolved version of everything in the root folder too Console.WriteLine("Resolve the placeholder"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", ""); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestResolved.Imports.Add("cdm:/foundations.cdm.json"); Console.WriteLine("Save the documents"); foreach (CdmEntityDeclarationDefinition eDef in manifestResolved.Entities) { // Get the entity being pointed at var localEDef = eDef; var entDef = await cdmCorpus.FetchObjectAsync <CdmEntityDefinition>(localEDef.EntityPath, manifestResolved); // Make a fake partition, just to demo that var part = cdmCorpus.MakeObject <CdmDataPartitionDefinition>(CdmObjectType.DataPartitionDef, $"{entDef.EntityName}-data-description"); localEDef.DataPartitions.Add(part); part.Explanation = "not real data, just for demo"; // Define the location of the partition, relative to the manifest var location = $"local:/{entDef.EntityName}/partition-data.csv"; part.Location = cdmCorpus.Storage.CreateRelativeCorpusPath(location, manifestResolved); // Add trait to partition for csv params var csvTrait = part.ExhibitsTraits.Add("is.partition.format.CSV", false); csvTrait.Arguments.Add("columnHeaders", "true"); csvTrait.Arguments.Add("delimiter", ","); // Get the actual location of the partition file from the corpus string partPath = cdmCorpus.Storage.CorpusPathToAdapterPath(location); // Make a fake file with nothing but header for columns string header = ""; foreach (CdmTypeAttributeDefinition att in entDef.Attributes) { if (header != "") { header += ","; } header += att.Name; } Directory.CreateDirectory(cdmCorpus.Storage.CorpusPathToAdapterPath($"local:/{ entDef.EntityName}")); File.WriteAllText(partPath, header); } await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); }
private async Task CreateManifest(CdmCorpusDefinition cdmCorpus) { Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add each declaration, this example is about medical appointments and care plans manifestAbstract.Entities.Add("Account", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Account.cdm.json/Account"); manifestAbstract.Entities.Add("Address", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Address.cdm.json/Address"); manifestAbstract.Entities.Add("CarePlan", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/CarePlan.cdm.json/CarePlan"); manifestAbstract.Entities.Add("CodeableConcept", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/CodeableConcept.cdm.json/CodeableConcept"); manifestAbstract.Entities.Add("Contact", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Contact.cdm.json/Contact"); manifestAbstract.Entities.Add("Device", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Device.cdm.json/Device"); manifestAbstract.Entities.Add("EmrAppointment", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/EmrAppointment.cdm.json/EmrAppointment"); manifestAbstract.Entities.Add("Encounter", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Encounter.cdm.json/Encounter"); manifestAbstract.Entities.Add("EpisodeOfCare", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/EpisodeOfCare.cdm.json/EpisodeOfCare"); manifestAbstract.Entities.Add("Location", "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Location.cdm.json/Location"); // Add the temp manifest to the root of the local documents in the corpus. var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract); // Create the resolved version of everything in the root folder too Console.WriteLine("Resolve the placeholder"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", ""); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestResolved.Imports.Add("cdm:/foundations.cdm.json"); Console.WriteLine("Save the documents"); foreach (CdmEntityDeclarationDefinition eDef in manifestResolved.Entities) { // Get the entity being pointed at var localEDef = eDef; var entDef = await cdmCorpus.FetchObjectAsync <CdmEntityDefinition>(localEDef.EntityPath, manifestResolved); // Make a fake partition, just to demo that var part = cdmCorpus.MakeObject <CdmDataPartitionDefinition>(CdmObjectType.DataPartitionDef, $"{entDef.EntityName}-data-description"); localEDef.DataPartitions.Add(part); part.Explanation = "not real data, just for demo"; // Define the location of the partition, relative to the manifest var location = $"local:/{entDef.EntityName}/partition-data.csv"; part.Location = cdmCorpus.Storage.CreateRelativeCorpusPath(location, manifestResolved); // Add trait to partition for csv params var csvTrait = part.ExhibitsTraits.Add("is.partition.format.CSV", false) as CdmTraitReference; csvTrait.Arguments.Add("columnHeaders", "true"); csvTrait.Arguments.Add("delimiter", ","); // Get the actual location of the partition file from the corpus string partPath = cdmCorpus.Storage.CorpusPathToAdapterPath(location); // Make a fake file with nothing but header for columns string header = ""; foreach (CdmTypeAttributeDefinition att in entDef.Attributes) { if (header != "") { header += ","; } header += att.Name; } Directory.CreateDirectory(cdmCorpus.Storage.CorpusPathToAdapterPath($"local:/{entDef.EntityName}")); File.WriteAllText(partPath, header); } await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); }
public async Task TestConditionalProjUsingObjectModel() { string testName = "TestConditionalProjUsingObjectModel"; CdmCorpusDefinition corpus = ProjectionTestUtils.GetCorpus(testName, testsSubpath); CdmFolderDefinition localRoot = corpus.Storage.FetchRootFolder("local"); // Create an entity. CdmEntityDefinition entity = ProjectionTestUtils.CreateEntity(corpus, localRoot); // Create a projection with a condition that states the operation should only execute when the resolution directive is 'structured'. CdmProjection projection = ProjectionTestUtils.CreateProjection(corpus, localRoot); projection.Condition = "structured==true"; // Create an AddAttributeGroup operation CdmOperationAddAttributeGroup addAttGroupOp = corpus.MakeObject <CdmOperationAddAttributeGroup>(CdmObjectType.OperationAddAttributeGroupDef); addAttGroupOp.AttributeGroupName = "PersonAttributeGroup"; projection.Operations.Add(addAttGroupOp); // Create an entity reference to hold this projection. CdmEntityReference projectionEntityRef = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef.ExplicitReference = projection; // Create an entity attribute that contains this projection and add this to the entity. CdmEntityAttributeDefinition entityAttribute = corpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, "TestEntityAttribute"); entityAttribute.Entity = projectionEntityRef; entity.Attributes.Add(entityAttribute); // Create resolution options with the 'referenceOnly' directive. ResolveOptions resOpt = new ResolveOptions(entity.InDocument) { Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "referenceOnly" }) }; // Resolve the entity with 'referenceOnly' CdmEntityDefinition resolvedEntityWithReferenceOnly = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", resOpt, localRoot); // Verify correctness of the resolved attributes after running the AddAttributeGroup operation // Original set of attributes: ["id", "name", "value", "date"] // Condition not met, keep attributes in flat list Assert.AreEqual(4, resolvedEntityWithReferenceOnly.Attributes.Count); Assert.AreEqual("id", (resolvedEntityWithReferenceOnly.Attributes[0] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("name", (resolvedEntityWithReferenceOnly.Attributes[1] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("value", (resolvedEntityWithReferenceOnly.Attributes[2] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("date", (resolvedEntityWithReferenceOnly.Attributes[3] as CdmTypeAttributeDefinition).Name); // Now resolve the entity with the 'structured' directive resOpt.Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "structured" }); CdmEntityDefinition resolvedEntityWithStructured = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", resOpt, localRoot); // Verify correctness of the resolved attributes after running the AddAttributeGroup operation // Original set of attributes: ["id", "name", "value", "date"] // Condition met, put all attributes in an attribute group CdmAttributeGroupDefinition attGroupDefinition = this.ValidateAttributeGroup(resolvedEntityWithStructured.Attributes, "PersonAttributeGroup"); Assert.AreEqual(4, attGroupDefinition.Members.Count); Assert.AreEqual("id", (attGroupDefinition.Members[0] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("name", (attGroupDefinition.Members[1] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("value", (attGroupDefinition.Members[2] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("date", (attGroupDefinition.Members[3] as CdmTypeAttributeDefinition).Name); }
public async Task TestConditionalProjUsingObjectModel() { string testName = nameof(TestConditionalProjUsingObjectModel); CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(testsSubpath, testName); CdmFolderDefinition localRoot = corpus.Storage.FetchRootFolder("local"); corpus.Storage.Mount("traitGroup", new LocalAdapter(traitGroupFilePath)); // Create an entity. CdmEntityDefinition entity = ProjectionTestUtils.CreateEntity(corpus, localRoot); entity.InDocument.Imports.Add("traitGroup:/TraitGroup.cdm.json"); // Create a projection with a condition that states the operation should only execute when the resolution directive is 'structured'. CdmProjection projection = ProjectionTestUtils.CreateProjection(corpus, localRoot); projection.Condition = "structured==true"; projection.RunSequentially = true; // Create an AlterTraits operation CdmOperationAlterTraits alterTraitsOp_1 = corpus.MakeObject <CdmOperationAlterTraits>(CdmObjectType.OperationAlterTraitsDef); alterTraitsOp_1.TraitsToAdd = new CdmCollection <CdmTraitReferenceBase>(corpus.Ctx, alterTraitsOp_1, CdmObjectType.TraitRef); alterTraitsOp_1.TraitsToAdd.Add(corpus.MakeRef <CdmTraitReference>(CdmObjectType.TraitRef, "means.TraitG100", true)); alterTraitsOp_1.TraitsToAdd.Add(corpus.MakeRef <CdmTraitGroupReference>(CdmObjectType.TraitGroupRef, "JobTitleBase", true)); alterTraitsOp_1.TraitsToRemove = new CdmCollection <CdmTraitReferenceBase>(corpus.Ctx, alterTraitsOp_1, CdmObjectType.TraitRef); alterTraitsOp_1.TraitsToRemove.Add(corpus.MakeRef <CdmTraitReference>(CdmObjectType.TraitRef, "means.TraitG300", true)); projection.Operations.Add(alterTraitsOp_1); CdmOperationAlterTraits alterTraitsOp_2 = corpus.MakeObject <CdmOperationAlterTraits>(CdmObjectType.OperationAlterTraitsDef); var traitG4 = corpus.MakeRef <CdmTraitReference>(CdmObjectType.TraitRef, "means.TraitG4", true); traitG4.Arguments.Add("precision", "5"); traitG4.Arguments.Add("scale", "15"); alterTraitsOp_2.TraitsToAdd = new CdmCollection <CdmTraitReferenceBase>(corpus.Ctx, alterTraitsOp_2, CdmObjectType.TraitRef); alterTraitsOp_2.TraitsToAdd.Add(traitG4); alterTraitsOp_2.ApplyTo = new List <string>() { "name" }; projection.Operations.Add(alterTraitsOp_2); // Create an entity reference to hold this projection. CdmEntityReference projectionEntityRef = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef.ExplicitReference = projection; // Create an entity attribute that contains this projection and add this to the entity. CdmEntityAttributeDefinition entityAttribute = corpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, "TestEntityAttribute"); entityAttribute.Entity = projectionEntityRef; entity.Attributes.Add(entityAttribute); // Create resolution options with the 'referenceOnly' directive. ResolveOptions resOpt = new ResolveOptions(entity.InDocument) { Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "referenceOnly" }) }; CdmEntityDefinition resolvedEntityWithReferenceOnly = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", resOpt, localRoot); // Original set of attributes: ["name", "age", "address", "phoneNumber", "email"] // Condition not met, no traits are added Assert.AreEqual(4, resolvedEntityWithReferenceOnly.Attributes.Count); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithReferenceOnly.Attributes[0], "id", doesNotExist: true); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithReferenceOnly.Attributes[1], "name", doesNotExist: true); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithReferenceOnly.Attributes[2], "value", doesNotExist: true); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithReferenceOnly.Attributes[3], "date", doesNotExist: true); CdmEntityDefinition resolvedEntityWithStructured = await ProjectionTestUtils.GetResolvedEntity(corpus, entity, new List <string> { "structured" }); // Original set of attributes: ["name", "age", "address", "phoneNumber", "email"] // Condition met, new traits are added Assert.AreEqual(4, resolvedEntityWithStructured.Attributes.Count); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithStructured.Attributes[0], "id"); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithStructured.Attributes[1], "name", true); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithStructured.Attributes[2], "value"); ValidateTrait((CdmTypeAttributeDefinition)resolvedEntityWithStructured.Attributes[3], "date"); }
public async Task TestWithoutNesting() { CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(testsSubpath, "TestEventList"); corpus.SetEventCallback(eventCallback, CdmStatusLevel.Warning, DummyCorrelationId); // Test fetching an object from invalid namespace results in at least one error message in the recorder _ = await corpus.FetchObjectAsync <CdmDocumentDefinition>("foo:/bar"); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrStorageNamespaceNotRegistered); // Test fetching a good object, this should leave event recorder empty _ = await corpus.FetchObjectAsync <CdmDocumentDefinition>("local:/default.manifest.cdm.json"); TestNoLogsState(corpus); // Test saving a manifest to invalid namespace results in at least one error message in the recorder var manifest = corpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "dummy"); await manifest.SaveAsAsync("foo:/bar", true); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrValdnMissingDoc); // Test resolving a manifest not added to a folder, this should yield at least one error message in the recorder await manifest.CreateResolvedManifestAsync("new dummy", null); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrResolveManifestFailed); // Test resolving an entity without WRT doc, this should yield at least one error message in the recorder var entity2 = corpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, "MyEntity2"); await entity2.CreateResolvedEntityAsync("MyEntity2-Resolved"); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrDocWrtDocNotfound); // Test invoking FileStatusCheckAsync on the manifest, this should yield at least one error message in the recorder await manifest.FileStatusCheckAsync(); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrStorageNullNamespace); // Repeat the same test but with status level 'None', no events should be recorded corpus.Ctx.ReportAtLevel = CdmStatusLevel.None; await entity2.CreateResolvedEntityAsync("MyEntity2-Resolved"); TestNoLogsState(corpus); // Test checking file status on a data partition // We're at log level 'Progress', so we get the EnterScope/LeaveScope messages too corpus.Ctx.ReportAtLevel = CdmStatusLevel.Progress; var part = corpus.MakeObject <CdmDataPartitionDefinition>(CdmObjectType.DataPartitionDef, "part"); await part.FileStatusCheckAsync(); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrPathNullObjectPath); // Test checking file status on a data partition pattern var refDoc = corpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, "RefEntDoc"); var partPattern = corpus.MakeObject <CdmDataPartitionPatternDefinition>(CdmObjectType.DataPartitionPatternDef, "partPattern"); partPattern.InDocument = refDoc; await partPattern.FileStatusCheckAsync(); TestBasicLogsState(corpus); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrStorageNullNamespace); TestHelper.AssertCdmLogCodeEquality(corpus, CdmLogCode.ErrDocAdapterNotFound); // Test calculating relationships - no errors/warnings await corpus.CalculateEntityGraphAsync(manifest); TestBasicLogsState(corpus); // Test populating relationships in manifest - no errors/warnings await manifest.PopulateManifestRelationshipsAsync(); TestBasicLogsState(corpus); }
static async Task Main(string[] args) { // Make a corpus, the corpus is the collection of all documents and folders created or discovered while navigating objects and paths var cdmCorpus = new CdmCorpusDefinition(); Console.WriteLine("Configure storage adapters"); // Configure storage adapters to point at the target local manifest location and at the fake public standards string pathFromExeToExampleRoot = "../../../../../../"; string sampleEntityName = "Account"; // Mount is as a local device. cdmCorpus.Storage.Mount("local", new LocalAdapter(pathFromExeToExampleRoot + "7-search-partition-pattern")); cdmCorpus.Storage.DefaultNamespace = "local"; // local is our default. so any paths that start out navigating without a device tag will assume local // Fake cdm, normaly use the github adapter // Mount it as the 'cdm' device, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "example-public-standards")); // Example how to mount to the ADLS. // cdmCorpus.Storage.Mount("adls", // new ADLSAdapter( // "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. // "/<FILESYSTEM-NAME>", // Root. // "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. // "<CLIENT-ID>", // Client ID. // "<CLIENT-SECRET>" // Client secret. // )); Console.WriteLine("Make placeholder manifest"); // make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local documents in the corpus. var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract, "tempAbstract.manifest.cdm.json"); // Add an entity named Account from some public standards Console.WriteLine("Add an entity named Account from some public standards"); var personDeclarationDefinition = manifestAbstract.Entities.Add(sampleEntityName, "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Account.cdm.json/Account"); // Create a data partition pattern var dataPartitionPattern = cdmCorpus.MakeObject <CdmDataPartitionPatternDefinition>(CdmObjectType.DataPartitionPatternDef, "sampleDataPartitionPattern", false); dataPartitionPattern.RootLocation = "local:dataFiles"; dataPartitionPattern.RegularExpression = "/(\\d{4})/(\\w+)/cohort(\\d+)\\.csv$"; Console.WriteLine($" Assign regular expression of the data partition pattern to: {dataPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the data partition pattern to: {dataPartitionPattern.RootLocation}"); dataPartitionPattern.Explanation = "/ capture 4 digits / capture a word / capture one or more digits after the word cohort but before .csv"; dataPartitionPattern.Parameters = new List <string> { "year", "month", "cohortNumber" }; // Add the data partition pattern we just created to the entity data partition pattern collection personDeclarationDefinition.DataPartitionPatterns.Add(dataPartitionPattern); // Calling FileStatusCheckAsync to pick up the all data partition files which names match the data partition pattern, // and add them to the entity in the manifest await manifestAbstract.FileStatusCheckAsync(); // List all data partition locations. Console.WriteLine($"\nlist of all data partition locations for the entity Account matches the data partition pattern:"); foreach (CdmDataPartitionDefinition dataPartition in personDeclarationDefinition.DataPartitions) { Console.WriteLine($" {dataPartition.Location}"); } Console.WriteLine("Resolve the manifest"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); // You can save the doc as a model.json format as an option // await manifestResolved.SaveAsAsync("model.json", true); }
public async Task TestWithoutNesting() { CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(testsSubpath, "TestEventList"); corpus.SetEventCallback(eventCallback, CdmStatusLevel.Warning, DummyCorrelationId); // Test fetching an object from invalid namespace results in at least one error message in the recorder _ = await corpus.FetchObjectAsync <CdmDocumentDefinition>("foo:/bar"); Assert.IsNotNull(corpus.Ctx.Events, "Ctx.Events should not be null"); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count > 0, "There should have been at least one event recorded when fetching object with incorrect path"); Assert.IsTrue(corpus.Ctx.Events[0].ContainsKey("timestamp"), "The recorded event should have had a timestamp key"); Assert.IsTrue(corpus.Ctx.Events[0]["correlationId"] == DummyCorrelationId, "The recorded event should have had a correlationId key with the dummy value"); // Test fetching a good object, this should leave event recorder empty _ = await corpus.FetchObjectAsync <CdmDocumentDefinition>("local:/default.manifest.cdm.json"); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count == 0, "There should have been no events recorded when fetching object with correct path"); // Test saving a manifest to invalid namespace results in at least one error message in the recorder var manifest = corpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "dummy"); await manifest.SaveAsAsync("foo:/bar", true); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count > 0, "There should have been at least one event recorded"); Assert.IsTrue(corpus.Ctx.Events[0].ContainsKey("timestamp"), "The recorded event should have had a timestamp key"); Assert.IsTrue(corpus.Ctx.Events[0]["correlationId"] == DummyCorrelationId, "The recorded event should have had a correlationId key with the dummy value"); // Test resolving a manifest not added to a folder, this should yield at least one error message in the recorder await manifest.CreateResolvedManifestAsync("new dummy", null); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count > 0, "There should have been at least one event recorded"); Assert.IsTrue(corpus.Ctx.Events[0].ContainsKey("timestamp"), "The recorded event should have had a timestamp key"); Assert.IsTrue(corpus.Ctx.Events[0]["correlationId"] == DummyCorrelationId, "The recorded event should have had a correlationId key with the dummy value"); // Test resolving an entity without WRT doc, this should yield at least one error message in the recorder var entity2 = corpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, "MyEntity2"); await entity2.CreateResolvedEntityAsync("MyEntity2-Resolved"); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count > 0, "There should have been at least one event recorded"); Assert.IsTrue(corpus.Ctx.Events[0].ContainsKey("timestamp"), "The recorded event should have had a timestamp key"); Assert.IsTrue(corpus.Ctx.Events[0]["correlationId"] == DummyCorrelationId, "The recorded event should have had a correlationId key with the dummy value"); // Test invoking FileStatusCheckAsync on the manifest, this should yield at least one error message in the recorder await manifest.FileStatusCheckAsync(); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count > 0, "There should have been at least one event recorded"); Assert.IsTrue(corpus.Ctx.Events[0].ContainsKey("timestamp"), "The recorded event should have had a timestamp key"); Assert.IsTrue(corpus.Ctx.Events[0]["correlationId"] == DummyCorrelationId, "The recorded event should have had a correlationId key with the dummy value"); // Repeat the same test but with status level 'None', no events should be recorded corpus.Ctx.ReportAtLevel = CdmStatusLevel.None; await entity2.CreateResolvedEntityAsync("MyEntity2-Resolved"); Assert.IsFalse(corpus.Ctx.Events.IsRecording, "Recording should be disabled at the end of API call"); Assert.IsTrue(corpus.Ctx.Events.Count == 0, "There should have been no events recorded when fetching object with correct path"); }
/// <summary> /// Create a projection object with operations /// </summary> /// <param name="corpus"></param> /// <returns></returns> private CdmProjection CreateProjectionWithOperationCollection(CdmCorpusDefinition corpus, CdmObject owner) { CdmProjection projection = corpus.MakeObject <CdmProjection>(CdmObjectType.ProjectionDef); { projection.Source = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, "TestSource", simpleNameRef: true); } { // AddCountAttribute Operation CdmOperationAddCountAttribute addCountAttributeOp = new CdmOperationAddCountAttribute(corpus.Ctx) { CountAttribute = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef) }; projection.Operations.Add(addCountAttributeOp); // AddSupportingAttribute Operation CdmOperationAddSupportingAttribute addSupportingAttributesOp = new CdmOperationAddSupportingAttribute(corpus.Ctx) { SupportingAttribute = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef) }; projection.Operations.Add(addSupportingAttributesOp); // AddTypeAttribute Operation CdmOperationAddTypeAttribute addTypeAttributeOp = new CdmOperationAddTypeAttribute(corpus.Ctx) { TypeAttribute = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef) }; projection.Operations.Add(addTypeAttributeOp); // ExcludeAttributes Operation CdmOperationExcludeAttributes excludeAttributesOp = new CdmOperationExcludeAttributes(corpus.Ctx) { ExcludeAttributes = new List <string>() }; excludeAttributesOp.ExcludeAttributes.Add("testAttribute1"); projection.Operations.Add(excludeAttributesOp); // ArrayExpansion Operation CdmOperationArrayExpansion arrayExpansionOp = new CdmOperationArrayExpansion(corpus.Ctx) { StartOrdinal = 0, EndOrdinal = 1 }; projection.Operations.Add(arrayExpansionOp); // CombineAttributes Operation CdmOperationCombineAttributes combineAttributesOp = new CdmOperationCombineAttributes(corpus.Ctx) { Take = new List <string>(), MergeInto = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef) }; combineAttributesOp.Take.Add("testAttribute1"); projection.Operations.Add(combineAttributesOp); // RenameAttributes Operation CdmOperationRenameAttributes renameAttributesOp = new CdmOperationRenameAttributes(corpus.Ctx) { RenameFormat = "{m}" }; projection.Operations.Add(renameAttributesOp); // ReplaceAsForeignKey Operation CdmOperationReplaceAsForeignKey replaceAsForeignKeyOp = new CdmOperationReplaceAsForeignKey(corpus.Ctx) { Reference = "testAttribute1", ReplaceWith = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, "testForeignKey", simpleNameRef: false) }; projection.Operations.Add(replaceAsForeignKeyOp); // IncludeAttributes Operation CdmOperationIncludeAttributes includeAttributesOp = new CdmOperationIncludeAttributes(corpus.Ctx) { IncludeAttributes = new List <string>() }; includeAttributesOp.IncludeAttributes.Add("testAttribute1"); projection.Operations.Add(includeAttributesOp); } return(projection); }
private async Task CustomizeEntities(CdmCorpusDefinition cdmCorpus) { // Open the default manifest at the root, used later when done // This method turns relative corpus paths into absolute ones in case we are in some sub-folders and don't know it var manifest = await cdmCorpus.FetchObjectAsync <CdmManifestDefinition>("default.manifest.cdm.json"); Console.WriteLine("Define new extension"); // First we will make a new document right in the same folder as the manifest var docAbs = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, "MobileCareTeam.cdm.json"); // Import the cdm description of the original so the symbols will resolve docAbs.Imports.Add("cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/CareTeam.cdm.json", null); // We will make a new trait to identify things that are known to be temporary, used later // In theory this would be defined somewhere central so it can be shared var traitTemp = docAbs.Definitions.Add(CdmObjectType.TraitDef, "means.temporary") as CdmTraitDefinition; // Extends the standard 'means' base trait traitTemp.ExtendsTrait = cdmCorpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, "means", true); // Add a parameter for the expected duration in days var param = cdmCorpus.MakeObject <CdmParameterDefinition>(CdmObjectType.ParameterDef, "estimatedDays"); // By not using "true" on the last arg, this becomes an real reference object in the json. go look at the difference from "means" when this is done param.DataTypeRef = cdmCorpus.MakeObject <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "integer"); param.DefaultValue = "30"; traitTemp.Parameters.Add(param); // Make an entity definition and add it to the list of definitions in the document. CdmEntityDefinition entAbs = docAbs.Definitions.Add(CdmObjectType.EntityDef, "MobileCareTeam") as CdmEntityDefinition; // This entity extends the standard // This function with 'true' will make a simple reference to the base entAbs.ExtendsEntity = cdmCorpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, "CareTeam", true); // and we will add an attribute CdmTypeAttributeDefinition attNew = cdmCorpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, "currentCity"); // The attribute is a type is 'City" this is one of the predefined semantic types in meanings.cdm.json attNew.DataType = cdmCorpus.MakeObject <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "city", true); attNew.Description = "The current city where the mobile care team is working."; // also apply our fancy new 'temporary' trait. they stay in a city for 90 days on average CdmTraitReference tr = cdmCorpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, "means.temporary"); tr.Arguments.Add("estimatedDays", "90"); attNew.AppliedTraits.Add(tr); // Add attribute to the entity entAbs.Attributes.Add(attNew); // The entity abstract definition is done, add the document to the corpus in the root folder and then save that doc cdmCorpus.Storage.FetchRootFolder("local").Documents.Add(docAbs); // next step is to remove all of the guesswork out of decoding the entity shape by 'resolving' it to a relational by reference shape Console.WriteLine("Make a local 'resolved' copy"); // Now resolve it // Made the entity and document have a different name to avoid conflicts in this folder var entFlat = await entAbs.CreateResolvedEntityAsync("LocalMobileCareTeam"); // Now just add the pointer into our manifest. Console.WriteLine("Add to manifest"); manifest.Entities.Add(entFlat); // This function will update all of the fileStatus times in the manifest // await manifest.RefreshAsync(null); // Save the manifest along with linked definition files. await manifest.SaveAsAsync("default-resolved.manifest.cdm.json", true); }
public async Task TestConditionalProjUsingObjectModel() { CdmCorpusDefinition corpus = ProjectionTestUtils.GetLocalCorpus(testsSubpath, "TestConditionalProjUsingObjectModel"); corpus.Storage.Mount("local", new LocalAdapter(TestHelper.GetActualOutputFolderPath(testsSubpath, "TestConditionalProjUsingObjectModel"))); CdmFolderDefinition localRoot = corpus.Storage.FetchRootFolder("local"); // Create an entity CdmEntityDefinition entity = ProjectionTestUtils.CreateEntity(corpus, localRoot); // Create a projection with a condition that states the operation should only execute when the resolution directive is 'referenceOnly' CdmProjection projection = ProjectionTestUtils.CreateProjection(corpus, localRoot); projection.Condition = "referenceOnly==true"; // Create an AddTypeAttribute operation CdmOperationAddTypeAttribute addTypeAttrOp = corpus.MakeObject <CdmOperationAddTypeAttribute>(CdmObjectType.OperationAddTypeAttributeDef); addTypeAttrOp.TypeAttribute = corpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, "testType"); addTypeAttrOp.TypeAttribute.DataType = corpus.MakeRef <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "entityName", true); projection.Operations.Add(addTypeAttrOp); // Create an entity reference to hold this projection CdmEntityReference projectionEntityRef = corpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, null); projectionEntityRef.ExplicitReference = projection; // Create an entity attribute that contains this projection and add this to the entity CdmEntityAttributeDefinition entityAttribute = corpus.MakeObject <CdmEntityAttributeDefinition>(CdmObjectType.EntityAttributeDef, "TestEntityAttribute"); entityAttribute.Entity = projectionEntityRef; entity.Attributes.Add(entityAttribute); // Create resolution options with the 'referenceOnly' directive ResolveOptions resOpt = new ResolveOptions(entity.InDocument); resOpt.Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "referenceOnly" }); // Resolve the entity with 'referenceOnly' CdmEntityDefinition resolvedEntityWithReferenceOnly = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", resOpt, localRoot); // Verify correctness of the resolved attributes after running the AddTypeAttribute operation // Original set of attributes: ["id", "name", "value", "date"] // Type attribute: "testType" Assert.AreEqual(5, resolvedEntityWithReferenceOnly.Attributes.Count); Assert.AreEqual("id", (resolvedEntityWithReferenceOnly.Attributes[0] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("name", (resolvedEntityWithReferenceOnly.Attributes[1] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("value", (resolvedEntityWithReferenceOnly.Attributes[2] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("date", (resolvedEntityWithReferenceOnly.Attributes[3] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("testType", (resolvedEntityWithReferenceOnly.Attributes[4] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("is.linkedEntity.name", resolvedEntityWithReferenceOnly.Attributes[4].AppliedTraits[4].NamedReference); // Now resolve the entity with the 'structured' directive resOpt.Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "structured" }); CdmEntityDefinition resolvedEntityWithStructured = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", resOpt, localRoot); // Verify correctness of the resolved attributes after running the AddTypeAttribute operation // Original set of attributes: ["id", "name", "value", "date"] // No Type attribute added, condition was false Assert.AreEqual(4, resolvedEntityWithStructured.Attributes.Count); Assert.AreEqual("id", (resolvedEntityWithStructured.Attributes[0] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("name", (resolvedEntityWithStructured.Attributes[1] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("value", (resolvedEntityWithStructured.Attributes[2] as CdmTypeAttributeDefinition).Name); Assert.AreEqual("date", (resolvedEntityWithStructured.Attributes[3] as CdmTypeAttributeDefinition).Name); }
static async Task Main() { // Make a corpus, the corpus is the collection of all documents and folders created or discovered while navigating objects and paths var cdmCorpus = new CdmCorpusDefinition(); Console.WriteLine("Configuring storage adapters"); // Configure storage adapters to point at the target local manifest location and at the fake public standards var pathFromExeToExampleRoot = "../"; cdmCorpus.Storage.Mount("local", new LocalAdapter(pathFromExeToExampleRoot + "output")); cdmCorpus.Storage.DefaultNamespace = "local"; // local is our default. so any paths that start out navigating without a device tag will assume local // Fake cdm, normaly use the github adapter // Mount it as the 'cdm' device, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "base-files")); // Example how to mount to the ADLS. // cdmCorpus.Storage.Mount("adls", // new ADLSAdapter( // "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. // "/<FILESYSTEM-NAME>", // Root. // "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. // "<CLIENT-ID>", // Client ID. // "<CLIENT-SECRET>" // Client secret. // )); Console.WriteLine("Creating placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local documents in the corpus var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract, "TempAbstract.manifest.cdm.json"); //READ CSV - OBSERVE SCHEMA: "entity, atribute, datatype" every row, no headers Console.WriteLine("Loading CDM definition file"); List <string> entitylist = new List <string>(); List <string> attributelist = new List <string>(); List <string> datatypelist = new List <string>(); using (var reader = new System.IO.StreamReader(@"../cdmdefinition.csv")) { while (!reader.EndOfStream) { var line = reader.ReadLine(); var values = line.Split(','); entitylist.Add(values[0]); attributelist.Add(values[1]); datatypelist.Add(values[2]); } } // Create entities and add attributes string entityname; CdmEntityDefinition entity; bool isnew = true; for (int i = 0; i < entitylist.Count; i++) { isnew = true; entityname = entitylist[i]; Console.WriteLine("Creating " + entityname + " entity"); entity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, entityname, false); while (i == 0 || entitylist[i] == entitylist[i - 1] || isnew) { isnew = false; var attribute = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, attributelist[i], "hasA", datatypelist[i]); entity.Attributes.Add(attribute); i++; if (i == entitylist.Count) { break; } } if (i != entitylist.Count) { i--; } // Create the document which contains the entity var entitydoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{entityname}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely entitydoc.Imports.Add(FoundationJsonPath); entitydoc.Definitions.Add(entity); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(entitydoc, entitydoc.Name); // Add the entity to the manifest manifestAbstract.Entities.Add(entity); } //THIAGO - MANUAL BREAKDOWN BEFORE AUTOMATING /*var entityname = "FixedAssetMaster"; * var entity = cdmCorpus.MakeObject<CdmEntityDefinition>(CdmObjectType.EntityDef, entityname, false); * var attribute1 = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, "Attribute1", "hasA", "string"); * entity.Attributes.Add(attribute1); * var attribute2 = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, "Attribute2", "hasA", "string"); * entity.Attributes.Add(attribute2); * // Create the document which contains the entity * var entitydoc = cdmCorpus.MakeObject<CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{entityname}.cdm.json", false); * // Add an import to the foundations doc so the traits about partitons will resolve nicely * entitydoc.Imports.Add(FoundationJsonPath); * entitydoc.Definitions.Add(entity); * // Add the document to the root of the local documents in the corpus * localRoot.Documents.Add(entitydoc, entitydoc.Name); * // Add the entity to the manifest * manifestAbstract.Entities.Add(entity);*/ /* * // Create the simplest entity - CustomPerson * // Create the entity definition instance * var personEntity = cdmCorpus.MakeObject<CdmEntityDefinition>(CdmObjectType.EntityDef, CustomPersonEntityName, false); * // Add type attributes to the entity instance * var personAttributeId = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomPersonEntityName}Id", "identifiedBy", "entityId"); * personEntity.Attributes.Add(personAttributeId); * var personAttributeName = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomPersonEntityName}Name", "hasA", "string"); * personEntity.Attributes.Add(personAttributeName); * // Add properties to the entity instance * personEntity.DisplayName = CustomPersonEntityName; * personEntity.Version = "0.0.1"; * personEntity.Description = "This is a custom entity created for the sample."; * // Create the document which contains the entity * var personEntityDoc = cdmCorpus.MakeObject<CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{CustomPersonEntityName}.cdm.json", false); * // Add an import to the foundations doc so the traits about partitons will resolve nicely * personEntityDoc.Imports.Add(FoundationJsonPath); * personEntityDoc.Definitions.Add(personEntity); * // Add the document to the root of the local documents in the corpus * localRoot.Documents.Add(personEntityDoc, personEntityDoc.Name); * // Add the entity to the manifest * manifestAbstract.Entities.Add(personEntity); * * * // Create an entity - CustomAccount which has a relationship with the entity CustomPerson * // Create the entity definition instance * var accountEntity = cdmCorpus.MakeObject<CdmEntityDefinition>(CdmObjectType.EntityDef, CustomAccountEntityName, false); * // Add type attributes to the entity instance * var accountAttributeId = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomAccountEntityName}Id", "identifiedBy", "entityId"); * accountEntity.Attributes.Add(accountAttributeId); * var accountAttributeName = CreateEntityAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomAccountEntityName}Name", "hasA", "string"); * accountEntity.Attributes.Add(accountAttributeName); * // Add properties to the entity instance * accountEntity.DisplayName = CustomAccountEntityName; * accountEntity.Version = "0.0.1"; * accountEntity.Description = "This is a custom entity created for the sample."; * // In this sample, every account has one person who owns the account * // the relationship is actually an entity attribute * var attributeExplanation = "The owner of the account, which is a person."; * // You can all CreateSimpleAttributeForRelationshipBetweenTwoEntities() instead, but CreateAttributeForRelationshipBetweenTwoEntities() can show * // more details of how to use resolution guidance to customize your data * var accountOwnerAttribute = CreateAttributeForRelationshipBetweenTwoEntities(cdmCorpus, CustomPersonEntityName, "accountOwner", attributeExplanation); * accountEntity.Attributes.Add(accountOwnerAttribute); * // Create the document which contains the entity * var accountEntityDoc = cdmCorpus.MakeObject<CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{CustomAccountEntityName}.cdm.json", false); * // Add an import to the foundations doc so the traits about partitons will resolve nicely * accountEntityDoc.Imports.Add(FoundationJsonPath); * // the CustomAccount entity has a relationship with the CustomPerson entity, this relationship is defined from its attribute with traits, * // the import to the entity reference CustomPerson's doc is required * accountEntityDoc.Imports.Add($"{CustomPersonEntityName}.cdm.json"); * accountEntityDoc.Definitions.Add(accountEntity); * // Add the document to the root of the local documents in the corpus * localRoot.Documents.Add(accountEntityDoc, accountEntityDoc.Name); * // Add the entity to the manifest * manifestAbstract.Entities.Add(accountEntity); * * * // Create an entity which extends "Account" from the standard, it contains everything that "Account" has * var extendedStandardAccountEntity = cdmCorpus.MakeObject<CdmEntityDefinition>(CdmObjectType.EntityDef, ExtendedStandardAccount, false); * // This function with 'true' will make a simple reference to the base * extendedStandardAccountEntity.ExtendsEntity = cdmCorpus.MakeObject<CdmEntityReference>(CdmObjectType.EntityRef, "Account", true); * var attrExplanation = "This is a simple custom account for this sample."; * // Add a relationship from it to the CustomAccount entity, and name the foreign key to SimpleCustomAccount * // You can all CreateSimpleAttributeForRelationshipBetweenTwoEntities() instead, but CreateAttributeForRelationshipBetweenTwoEntities() can show * // more details of how to use resolution guidance to customize your data * var simpleCustomAccountAttribute = CreateAttributeForRelationshipBetweenTwoEntities(cdmCorpus, CustomAccountEntityName, "SimpleCustomAccount", attrExplanation); * extendedStandardAccountEntity.Attributes.Add(simpleCustomAccountAttribute); * var extendedStandardAccountEntityDoc = cdmCorpus.MakeObject<CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{ExtendedStandardAccount}.cdm.json", false); * // Add an import to the foundations doc so the traits about partitons will resolve nicely * extendedStandardAccountEntityDoc.Imports.Add(FoundationJsonPath); * // The ExtendedAccount entity extends from the "Account" entity from standards, the import to the entity Account's doc is required * // it also has a relationship with the CustomAccount entity, the relationship defined from its from its attribute with traits, the import to the entity reference CustomAccount's doc is required * extendedStandardAccountEntityDoc.Imports.Add($"{SchemaDocsRoot}/Account.cdm.json"); * extendedStandardAccountEntityDoc.Imports.Add($"{CustomAccountEntityName}.cdm.json"); * // Add the document to the root of the local documents in the corpus * localRoot.Documents.Add(extendedStandardAccountEntityDoc, extendedStandardAccountEntityDoc.Name); * extendedStandardAccountEntityDoc.Definitions.Add(extendedStandardAccountEntity); * // Add the entity to the manifest * manifestAbstract.Entities.Add(extendedStandardAccountEntity); */ // Create the resolved version of everything in the root folder too Console.WriteLine("Resolving the placeholder"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestResolved.Imports.Add(FoundationJsonPath); Console.WriteLine("Saving the documents"); foreach (CdmEntityDeclarationDefinition eDef in manifestResolved.Entities) { // Get the entity being pointed at var localEDef = eDef; var entDef = await cdmCorpus.FetchObjectAsync <CdmEntityDefinition>(localEDef.EntityPath, manifestResolved); // Make a fake partition, just to demo that var part = cdmCorpus.MakeObject <CdmDataPartitionDefinition>(CdmObjectType.DataPartitionDef, $"{entDef.EntityName}-data-description"); localEDef.DataPartitions.Add(part); part.Explanation = "not real data, just for demo"; // We have existing partition files for the custom entities, so we need to make the partition point to the file location part.Location = $"local:/{entDef.EntityName}/partition-data.csv"; // Add trait to partition for csv params var csvTrait = part.ExhibitsTraits.Add("is.partition.format.CSV", false); csvTrait.Arguments.Add("columnHeaders", "true"); csvTrait.Arguments.Add("delimiter", ","); } // We can save the documents as manifest.cdm.json format or model.json // Save as manifest.cdm.json await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); // Save as a model.json // await manifestResolved.SaveAsAsync("model.json", true); Console.WriteLine("Finished"); Console.ReadKey(); }
private async Task SearchPartitionPattern(CdmCorpusDefinition cdmCorpus) { string sampleEntityName = "Account"; Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local documents in the corpus. var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract, "tempAbstract.manifest.cdm.json"); // Add an entity named Account from some public standards Console.WriteLine("Add an entity named Account from some public standards"); var accountDeclarationDefinition = manifestAbstract.Entities.Add(sampleEntityName, "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Account.cdm.json/Account"); // Create a data partition pattern var dataPartitionPattern = CreatePartitionPatternDefinition(cdmCorpus, "sampleDataPartitionPattern"); dataPartitionPattern.Explanation = "/ capture 4 digits / capture a word / capture one or more digits after the word cohort but before .csv"; Console.WriteLine($" Assign regular expression of the data partition pattern to: {dataPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the data partition pattern to: {dataPartitionPattern.RootLocation}"); // Add the data partition pattern we just created to the entity data partition pattern collection accountDeclarationDefinition.DataPartitionPatterns.Add(dataPartitionPattern); // Create incremental partition patterns var upsertIncrementalPartitionPattern = CreatePartitionPatternDefinition(cdmCorpus, "UpsertPattern", true, true); AddIncrementalPartitionTrait(upsertIncrementalPartitionPattern, CdmIncrementalPartitionType.Upsert); Console.WriteLine($"\n Assign regular expression of the first incremental partition pattern to: {upsertIncrementalPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the first incremental partition pattern to: {upsertIncrementalPartitionPattern.RootLocation}"); var deleteIncrementalPartitionPattern = CreatePartitionPatternDefinition(cdmCorpus, "DeletePattern", true); AddIncrementalPartitionTrait(deleteIncrementalPartitionPattern, CdmIncrementalPartitionType.Delete, "FullDataPattern"); Console.WriteLine($"\n Assign regular expression of the second incremental partition pattern to: {deleteIncrementalPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the second incremental partition pattern to: {deleteIncrementalPartitionPattern.RootLocation}"); // Add the incremental partition patterns we just created to the entity increment partition pattern collection accountDeclarationDefinition.IncrementalPartitionPatterns.Add(upsertIncrementalPartitionPattern); accountDeclarationDefinition.IncrementalPartitionPatterns.Add(deleteIncrementalPartitionPattern); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestAbstract.Imports.Add("cdm:/foundations.cdm.json"); // Calling FileStatusCheckAsync to pick up the all data partition files which names match the data partition pattern, // and add them to the entity in the manifest await manifestAbstract.FileStatusCheckAsync(PartitionFileStatusCheckType.FullAndIncremental); // List all data partition locations. Console.WriteLine($"\nlist of all data partition locations for the entity Account matches the data partition pattern:"); foreach (CdmDataPartitionDefinition dataPartition in accountDeclarationDefinition.DataPartitions) { Console.WriteLine($" {dataPartition.Location}"); } // List all incremental partition locations. Console.WriteLine($"\nlist of all incremental partition locations for the entity Account matches the incremental partition pattern:"); foreach (CdmDataPartitionDefinition incrementalPartition in accountDeclarationDefinition.IncrementalPartitions) { Console.WriteLine($" {incrementalPartition.Location}"); } Console.WriteLine("Resolve the manifest"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); // You can save the doc as a model.json format as an option // await manifestResolved.SaveAsAsync("model.json", true); }
static async Task Main(string[] args) { var pathFromExeToExampleRoot = "../../../../../../"; // ------------------------------------------------------------------------------------------------------------ // Instantiate corpus and set up the default namespace to be local var cdmCorpus = new CdmCorpusDefinition(); cdmCorpus.Storage.DefaultNamespace = "local"; // ------------------------------------------------------------------------------------------------------------ // Set up adapters for managing access to different files-system locations // Fake cdm, normaly use the github adapter // Mount it as the 'cdm' device, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "example-public-standards")); cdmCorpus.Storage.Mount("local", new LocalAdapter(modelJsonRoot)); // Example how to mount to the ADLS - make sure the hostname and root entered here are also changed // in the example.model.json file we load in the next section cdmCorpus.Storage.Mount("adls", new ADLSAdapter( "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. "/<FILESYSTEM-NAME>", // Root. "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. "<CLIENT-ID>", // Client ID. "<CLIENT-SECRET>" // Client secret. )); // ------------------------------------------------------------------------------------------------------------ // Load a model.json file from local FS var manifest = await cdmCorpus.FetchObjectAsync <CdmManifestDefinition>("local:/model.json"); // ------------------------------------------------------------------------------------------------------------ // Explore entities and partitions defined in the model Console.WriteLine("Listing entity declarations:"); foreach (CdmEntityDeclarationDefinition decl in manifest.Entities) { Console.WriteLine(" " + decl.EntityName); // TODO: This can be rewritten in a different way since data partition gives null for referenced entities, suggestions are welcome. if (decl.ObjectType == CdmObjectType.LocalEntityDeclarationDef) { foreach (CdmDataPartitionDefinition dataPart in decl.DataPartitions) { Console.WriteLine(" " + dataPart.Location); } } } // ------------------------------------------------------------------------------------------------------------ // Make changes to the model // Create a new document where the new entity's definition will be stored var newEntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, "NewEntity.cdm.json", false); newEntityDoc.Imports.Add("cdm:/foundations.cdm.json"); cdmCorpus.Storage.FetchRootFolder("local").Documents.Add(newEntityDoc); var newEntity = newEntityDoc.Definitions.Add(CdmObjectType.EntityDef, "NewEntity") as CdmEntityDefinition; // Define new string attribute and add it to the entity definition var newAttribute = cdmCorpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, "NewAttribute", false); newAttribute.DataFormat = CdmDataFormat.String; newEntity.Attributes.Add(newAttribute); // Call will create EntityDeclarationDefinition based on entity definition and add it to manifest.Entities var newEntityDecl = manifest.Entities.Add(newEntity); // Define a partition and add it to the local declaration var newPartition = cdmCorpus.MakeObject <CdmDataPartitionDefinition>(CdmObjectType.DataPartitionDef, "NewPartition", false); newPartition.Location = "adls:/NewPartition.csv"; newEntityDecl.DataPartitions.Add(newPartition); // ------------------------------------------------------------------------------------------------------------ // Save the file to ADLSg2 - we achieve that by adding the manifest to the root folder of // the ADLS file-system and performing a save on the manifest CdmFolderDefinition adlsFolder = cdmCorpus.Storage.FetchRootFolder("adls"); adlsFolder.Documents.Add(manifest); await manifest.SaveAsAsync("model.json", true); }
static async Task Main(string[] args) { // Make a corpus, the corpus is the collection of all documents and folders created or discovered while navigating objects and paths var cdmCorpus = new CdmCorpusDefinition(); // set callback to receive error and warning logs. cdmCorpus.SetEventCallback(new EventCallback { Invoke = (level, message) => { Console.WriteLine(message); } }, CdmStatusLevel.Warning); Console.WriteLine("Configure storage adapters"); // Configure storage adapters to point at the target local manifest location and at the fake public standards string pathFromExeToExampleRoot = "../../../../../../../"; string sampleEntityName = "Account"; // Mount it as a local adapter. cdmCorpus.Storage.Mount("local", new LocalAdapter(pathFromExeToExampleRoot + "7-search-partition-pattern/sample-data")); cdmCorpus.Storage.DefaultNamespace = "local"; // local is our default. so any paths that start out navigating without a device tag will assume local // Fake cdm, normaly use the CDM Standards adapter // Mount it as the 'cdm' adapter, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "example-public-standards")); // Example how to mount to the ADLS. // cdmCorpus.Storage.Mount("adls", // new ADLSAdapter( // "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. // "/<FILESYSTEM-NAME>", // Root. // "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. // "<CLIENT-ID>", // Client ID. // "<CLIENT-SECRET>" // Client secret. // )); Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local documents in the corpus. var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract, "tempAbstract.manifest.cdm.json"); // Add an entity named Account from some public standards Console.WriteLine("Add an entity named Account from some public standards"); var accountDeclarationDefinition = manifestAbstract.Entities.Add(sampleEntityName, "cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/Account.cdm.json/Account"); // Create a data partition pattern var dataPartitionPattern = CreatePartitionPatternDefinition(cdmCorpus, "sampleDataPartitionPattern"); dataPartitionPattern.Explanation = "/ capture 4 digits / capture a word / capture one or more digits after the word cohort but before .csv"; Console.WriteLine($" Assign regular expression of the data partition pattern to: {dataPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the data partition pattern to: {dataPartitionPattern.RootLocation}"); // Add the data partition pattern we just created to the entity data partition pattern collection accountDeclarationDefinition.DataPartitionPatterns.Add(dataPartitionPattern); // Create incremental partition patterns var upsertIncrementalPartitionPattern = CreatePartitionPatternDefinition(cdmCorpus, "UpsertPattern", true, true); AddIncrementalPartitionTrait(upsertIncrementalPartitionPattern, CdmIncrementalPartitionType.Upsert); Console.WriteLine($"\n Assign regular expression of the first incremental partition pattern to: {upsertIncrementalPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the first incremental partition pattern to: {upsertIncrementalPartitionPattern.RootLocation}"); var deleteIncrementalPartitionPattern = CreatePartitionPatternDefinition(cdmCorpus, "DeletePattern", true); AddIncrementalPartitionTrait(deleteIncrementalPartitionPattern, CdmIncrementalPartitionType.Delete, "FullDataPattern"); Console.WriteLine($"\n Assign regular expression of the second incremental partition pattern to: {deleteIncrementalPartitionPattern.RegularExpression}"); Console.WriteLine($" Assign root location of the second incremental partition pattern to: {deleteIncrementalPartitionPattern.RootLocation}"); // Add the incremental partition patterns we just created to the entity increment partition pattern collection accountDeclarationDefinition.IncrementalPartitionPatterns.Add(upsertIncrementalPartitionPattern); accountDeclarationDefinition.IncrementalPartitionPatterns.Add(deleteIncrementalPartitionPattern); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestAbstract.Imports.Add("cdm:/foundations.cdm.json"); // Calling FileStatusCheckAsync to pick up the all data partition files which names match the data partition pattern, // and add them to the entity in the manifest await manifestAbstract.FileStatusCheckAsync(PartitionFileStatusCheckType.FullAndIncremental); // List all data partition locations. Console.WriteLine($"\nlist of all data partition locations for the entity Account matches the data partition pattern:"); foreach (CdmDataPartitionDefinition dataPartition in accountDeclarationDefinition.DataPartitions) { Console.WriteLine($" {dataPartition.Location}"); } // List all incremental partition locations. Console.WriteLine($"\nlist of all incremental partition locations for the entity Account matches the incremental partition pattern:"); foreach (CdmDataPartitionDefinition incrementalPartition in accountDeclarationDefinition.IncrementalPartitions) { Console.WriteLine($" {incrementalPartition.Location}"); } Console.WriteLine("Resolve the manifest"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); // You can save the doc as a model.json format as an option // await manifestResolved.SaveAsAsync("model.json", true); }
static async Task Main(string[] args) { // Make a corpus, the corpus is the collection of all documents and folders created or discovered while navigating objects and paths var cdmCorpus = new CdmCorpusDefinition(); Console.WriteLine("Configure storage adapters"); // Configure storage adapters to point at the target local manifest location and at the fake public standards string pathFromExeToExampleRoot = "../../../../../../"; // Mount is as a local device. cdmCorpus.Storage.Mount("local", new LocalAdapter(pathFromExeToExampleRoot + "3-customize-entities")); cdmCorpus.Storage.DefaultNamespace = "local"; // local is our default. so any paths that start out navigating without a device tag will assume local // Mount it as the 'cdm' device, not the default so must use "cdm:/folder" to get there cdmCorpus.Storage.Mount("cdm", new LocalAdapter(pathFromExeToExampleRoot + "example-public-standards")); // Example how to mount to the ADLS. // cdmCorpus.Storage.Mount("adls", // new ADLSAdapter( // "<ACCOUNT-NAME>.dfs.core.windows.net", // Hostname. // "/<FILESYSTEM-NAME>", // Root. // "72f988bf-86f1-41af-91ab-2d7cd011db47", // Tenant ID. // "<CLIENT-ID>", // Client ID. // "<CLIENT-SECRET>" // Client secret. // )); // Open the default manifest at the root, used later when done // This method turns relative corpus paths into absolute ones in case we are in some sub-folders and don't know it var manifest = await cdmCorpus.FetchObjectAsync <CdmManifestDefinition>("default.folio.cdm.json"); Console.WriteLine("Define new extension"); // First we will make a new document right in the same folder as the manifest var docAbs = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, "MobileCareTeam.cdm.json"); // Import the cdm description of the original so the symbols will resolve docAbs.Imports.Add("cdm:/core/applicationCommon/foundationCommon/crmCommon/accelerators/healthCare/electronicMedicalRecords/CareTeam.cdm.json", null); // We will make a new trait to identify things that are known to be temporary, used later // In theory this would be defined somewhere central so it can be shared var traitTemp = docAbs.Definitions.Add(CdmObjectType.TraitDef, "means.temporary") as CdmTraitDefinition; // Extends the standard 'means' base trait traitTemp.ExtendsTrait = cdmCorpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, "means", true); // Add a parameter for the expected duration in days var param = cdmCorpus.MakeObject <CdmParameterDefinition>(CdmObjectType.ParameterDef, "estimatedDays"); // By not using "true" on the last arg, this becomes an real reference object in the json. go look at the difference from "means" when this is done param.DataTypeRef = cdmCorpus.MakeObject <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "integer"); param.DefaultValue = "30"; traitTemp.Parameters.Add(param); // Make an entity definition and add it to the list of definitions in the document. CdmEntityDefinition entAbs = docAbs.Definitions.Add(CdmObjectType.EntityDef, "MobileCareTeam") as CdmEntityDefinition; // This entity extends the standard // This function with 'true' will make a simple reference to the base entAbs.ExtendsEntity = cdmCorpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, "CareTeam", true); // and we will add an attribute CdmTypeAttributeDefinition attNew = cdmCorpus.MakeObject <CdmTypeAttributeDefinition>(CdmObjectType.TypeAttributeDef, "currentCity"); // The attribute is a type is 'City" this is one of the predefined semantic types in meanings.cdm.json attNew.DataType = cdmCorpus.MakeObject <CdmDataTypeReference>(CdmObjectType.DataTypeRef, "city", true); attNew.Description = "The current city where the mobile care team is working"; // also apply our fancy new 'temporary' trait. they stay in a city for 90 days on average CdmTraitReference tr = cdmCorpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, "means.temporary"); tr.Arguments.Add("estimatedDays", "90"); attNew.AppliedTraits.Add(tr); // Add attribute to the entity entAbs.Attributes.Add(attNew); // The entity abstract definition is done, add the document to the corpus in the root folder and then save that doc cdmCorpus.Storage.FetchRootFolder("local").Documents.Add(docAbs); // next step is to remove all of the guesswork out of decoding the entity shape by 'resolving' it to a relational by reference shape Console.WriteLine("Make a local 'resolved' copy"); // Now resolve it // Made the entity and document have a different name to avoid conflicts in this folder var entFlat = await entAbs.CreateResolvedEntityAsync("LocalMobileCareTeam"); // Now just add the pointer into our manifest. Console.WriteLine("Add to manifest"); manifest.Entities.Add(entFlat); // This function will update all of the fileStatus times in the manifest // await manifest.RefreshFileStatus(); // Save the manifest along with linked definition files await manifest.SaveAsAsync("default.manifest.cdm.json", true); }
private async Task CreateNetNewEntities(CdmCorpusDefinition cdmCorpus) { Console.WriteLine("Make placeholder manifest"); // Make the temp manifest and add it to the root of the local documents in the corpus CdmManifestDefinition manifestAbstract = cdmCorpus.MakeObject <CdmManifestDefinition>(CdmObjectType.ManifestDef, "tempAbstract"); // Add the temp manifest to the root of the local adapter in the corpus var localRoot = cdmCorpus.Storage.FetchRootFolder("local"); localRoot.Documents.Add(manifestAbstract, "TempAbstract.manifest.cdm.json"); // Create two entities from scratch, and add some attributes, traits, properties, and relationships in between Console.WriteLine("Create net new entities"); // Create the simplest entity - CustomPerson // Create the entity definition instance var personEntity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, CustomPersonEntityName, false); // Add type attributes to the entity instance // Both purpose "identifiedBy" and data type "entityId" are defined in public standards on the document /samples/example-public-standards/primitives.cdm.json var personAttributeId = CreateTypeAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomPersonEntityName}Id", "identifiedBy", "entityId"); personEntity.Attributes.Add(personAttributeId); // Both purpose "hasA" and data type "name" are defined in public standards // The purpose "hasA" is from /samples/example-public-standards/primitives.cdm.json // The data type "name" is from /samples/example-public-standards/meanings.identity.cdm.json var personAttributeName = CreateTypeAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomPersonEntityName}Name", "hasA", "name"); personEntity.Attributes.Add(personAttributeName); // Add properties to the entity instance personEntity.DisplayName = CustomPersonEntityName; personEntity.Version = "0.0.1"; personEntity.Description = "This is a custom entity created for the sample."; // Create the document which contains the entity var personEntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{CustomPersonEntityName}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely personEntityDoc.Imports.Add(FoundationJsonPath); personEntityDoc.Definitions.Add(personEntity); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(personEntityDoc, personEntityDoc.Name); // Add the entity to the manifest manifestAbstract.Entities.Add(personEntity); // Create an entity - CustomAccount which has a relationship with the entity CustomPerson // Create the entity definition instance var accountEntity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, CustomAccountEntityName, false); // Add type attributes to the entity instance var accountAttributeId = CreateTypeAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomAccountEntityName}Id", "identifiedBy", "entityId"); accountEntity.Attributes.Add(accountAttributeId); var accountAttributeName = CreateTypeAttributeWithPurposeAndDataType(cdmCorpus, $"{CustomAccountEntityName}Name", "hasA", "name"); accountEntity.Attributes.Add(accountAttributeName); // Add properties to the entity instance accountEntity.DisplayName = CustomAccountEntityName; accountEntity.Version = "0.0.1"; accountEntity.Description = "This is a custom entity created for the sample."; // In this sample, every account has one person who owns the account // the relationship is actually an entity attribute var attributeExplanation = "The owner of the account, which is a person."; // You can call CreateSimpleAttributeForRelationshipBetweenTwoEntities() instead, but CreateEntityAttributeForRelationshipBetweenTwoEntities() can show // more details of how to use resolution guidance to customize your data var accountOwnerAttribute = CreateEntityAttributeForRelationshipBetweenTwoEntities(cdmCorpus, CustomPersonEntityName, "accountOwner", attributeExplanation); accountEntity.Attributes.Add(accountOwnerAttribute); // Create the document which contains the entity var accountEntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{CustomAccountEntityName}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely accountEntityDoc.Imports.Add(FoundationJsonPath); // The CustomAccount entity has a relationship with the CustomPerson entity, this relationship is defined from its attribute with traits, // the import to the entity reference CustomPerson's doc is required accountEntityDoc.Imports.Add($"{CustomPersonEntityName}.cdm.json"); accountEntityDoc.Definitions.Add(accountEntity); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(accountEntityDoc, accountEntityDoc.Name); // Add the entity to the manifest manifestAbstract.Entities.Add(accountEntity); // Create an entity which extends "Account" from the standard, it contains everything that "Account" has var extendedStandardAccountEntity = cdmCorpus.MakeObject <CdmEntityDefinition>(CdmObjectType.EntityDef, ExtendedStandardAccount, false); // This function with 'true' will make a simple reference to the base extendedStandardAccountEntity.ExtendsEntity = cdmCorpus.MakeObject <CdmEntityReference>(CdmObjectType.EntityRef, "Account", true); var attrExplanation = "This is a simple custom account for this sample."; // Add a relationship from it to the CustomAccount entity, and name the foreign key to SimpleCustomAccount // You can also call CreateEntityAttributeForRelationshipBetweenTwoEntities() instead like above var simpleCustomAccountAttribute = CreateSimpleEntityAttributeForRelationshipBetweenTwoEntities(cdmCorpus, CustomAccountEntityName, "SimpleCustomAccount", attrExplanation); extendedStandardAccountEntity.Attributes.Add(simpleCustomAccountAttribute); var extendedStandardAccountEntityDoc = cdmCorpus.MakeObject <CdmDocumentDefinition>(CdmObjectType.DocumentDef, $"{ExtendedStandardAccount}.cdm.json", false); // Add an import to the foundations doc so the traits about partitons will resolve nicely extendedStandardAccountEntityDoc.Imports.Add(FoundationJsonPath); // The ExtendedAccount entity extends from the "Account" entity from standards, the import to the entity Account's doc is required // it also has a relationship with the CustomAccount entity, the relationship defined from its from its attribute with traits, the import to the entity reference CustomAccount's doc is required extendedStandardAccountEntityDoc.Imports.Add($"{SchemaDocsRoot}/Account.cdm.json"); extendedStandardAccountEntityDoc.Imports.Add($"{CustomAccountEntityName}.cdm.json"); // Add the document to the root of the local documents in the corpus localRoot.Documents.Add(extendedStandardAccountEntityDoc, extendedStandardAccountEntityDoc.Name); extendedStandardAccountEntityDoc.Definitions.Add(extendedStandardAccountEntity); // Add the entity to the manifest manifestAbstract.Entities.Add(extendedStandardAccountEntity); // Create the resolved version of everything in the root folder too Console.WriteLine("Resolve the placeholder"); var manifestResolved = await manifestAbstract.CreateResolvedManifestAsync("default", null); // Add an import to the foundations doc so the traits about partitons will resolve nicely manifestResolved.Imports.Add(FoundationJsonPath); Console.WriteLine("Save the documents"); // We can save the documents as manifest.cdm.json format or model.json // Save as manifest.cdm.json await manifestResolved.SaveAsAsync($"{manifestResolved.ManifestName}.manifest.cdm.json", true); // Save as a model.json // await manifestResolved.SaveAsAsync("model.json", true); }