public static CdmOperationRenameAttributes FromData(CdmCorpusContext ctx, JToken obj)
        {
            if (obj == null)
            {
                return(null);
            }

            CdmOperationRenameAttributes renameAttributesOp = OperationBasePersistence.FromData <CdmOperationRenameAttributes>(ctx, CdmObjectType.OperationRenameAttributesDef, obj);

            renameAttributesOp.RenameFormat = obj["renameFormat"]?.ToString();

            if (obj["applyTo"] is JValue)
            {
                renameAttributesOp.ApplyTo = new List <string>
                {
                    (string)obj["applyTo"]
                };
            }
            else if (obj["applyTo"] is JArray applyToArray)
            {
                renameAttributesOp.ApplyTo = applyToArray.ToObject <List <string> >();
            }
            else if (obj["applyTo"] != null)
            {
                Logger.Error(nameof(OperationRenameAttributesPersistence), ctx, "Unsupported: applyTo property type should be string or List<string>.");
                return(null);
            }

            return(renameAttributesOp);
        }
예제 #2
0
        public static CdmOperationRenameAttributes FromData(CdmCorpusContext ctx, JToken obj)
        {
            if (obj == null)
            {
                return(null);
            }

            CdmOperationRenameAttributes renameAttributesOp = OperationBasePersistence.FromData <CdmOperationRenameAttributes>(ctx, CdmObjectType.OperationRenameAttributesDef, obj);

            renameAttributesOp.RenameFormat = obj["renameFormat"]?.ToString();

            if (obj["applyTo"] is JValue)
            {
                renameAttributesOp.ApplyTo = new List <string>
                {
                    (string)obj["applyTo"]
                };
            }
            else if (obj["applyTo"] is JArray applyToArray)
            {
                renameAttributesOp.ApplyTo = applyToArray.ToObject <List <string> >();
            }
            else if (obj["applyTo"] != null)
            {
                Logger.Error((ResolveContext)ctx, Tag, nameof(FromData), null, CdmLogCode.ErrPersistProjUnsupportedProp);
                return(null);
            }

            return(renameAttributesOp);
        }
예제 #3
0
        public async Task TestEntityProjUsingObjectModel()
        {
            CdmCorpusDefinition corpus = ProjectionTestUtils.GetLocalCorpus(testsSubpath, "TestEntityProjUsingObjectModel");

            corpus.Storage.Mount("local", new LocalAdapter(TestHelper.GetActualOutputFolderPath(testsSubpath, "TestEntityProjUsingObjectModel")));
            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;

            // Set the entity's ExtendEntity to be the projection
            entity.ExtendsEntity = projectionEntityRef2;

            // 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);
        }
예제 #4
0
        public static CdmOperationRenameAttributes FromData(CdmCorpusContext ctx, JToken obj)
        {
            if (obj == null)
            {
                return(null);
            }

            CdmOperationRenameAttributes renameAttributesOp = ctx.Corpus.MakeObject <CdmOperationRenameAttributes>(CdmObjectType.OperationRenameAttributesDef);


            if (obj["$type"] != null && !StringUtils.EqualsWithIgnoreCase(obj["$type"].ToString(), OperationTypeConvertor.OperationTypeToString(CdmOperationType.RenameAttributes)))
            {
                Logger.Error(nameof(OperationRenameAttributesPersistence), ctx, $"$type {obj["$type"].ToString()} is invalid for this operation.");
            }
            else
            {
                renameAttributesOp.Type = CdmOperationType.RenameAttributes;
            }
            if (obj["explanation"] != null)
            {
                renameAttributesOp.Explanation = (string)obj["explanation"];
            }
            renameAttributesOp.RenameFormat = obj["renameFormat"]?.ToString();
            renameAttributesOp.ApplyTo      = obj["applyTo"]?.ToObject <dynamic>();

            return(renameAttributesOp);
        }
예제 #5
0
        /// <summary>
        /// Applies the arrayExpansion operation to the entity attribute provided.
        /// It also takes care of applying a renameAttributes operation and optionally applying a addCountAttribute operation.
        /// </summary>
        /// <param name="entityAttr"></param>
        /// <param name="startOrdinal"></param>
        /// <param name="endOrdinal"></param>
        /// <param name="renameFormat"></param>
        /// <param name="countAttName"></param>
        static void ApplyArrayExpansion(CdmEntityAttributeDefinition entityAttr, int startOrdinal, int endOrdinal, string renameFormat, string countAttName)
        {
            var           ctx        = entityAttr.Ctx;
            CdmProjection projection = new CdmProjection(ctx)
            {
                Source          = entityAttr.Entity,
                RunSequentially = true,
                // Link for the Condition property documentation.
                // https://docs.microsoft.com/en-us/common-data-model/sdk/convert-logical-entities-resolved-entities#condition
                Condition = "!normalized"
            };

            entityAttr.Entity = new CdmEntityReference(ctx, projection, false);

            // Link for the ArrayExpansion operation documentation.
            // https://docs.microsoft.com/en-us/common-data-model/sdk/projections/arrayexpansion
            var arrExpansionOperation = new CdmOperationArrayExpansion(ctx)
            {
                StartOrdinal = startOrdinal,
                EndOrdinal   = endOrdinal
            };

            projection.Operations.Add(arrExpansionOperation);

            // Link for the RenameAttributes operation documentation.
            // https://docs.microsoft.com/en-us/common-data-model/sdk/projections/renameattributes
            // Doing an ArrayExpansion without a RenameAttributes afterwards will result in the expanded attributes being merged in the final resolved entity.
            // This is because ArrayExpansion does not rename the attributes it expands by default. The expanded attributes end up with the same name and gets merged.
            // Example: We expand A to A[1], A[2], A[3], but A[1], A[2], A[3] are still named "A".
            var renameAttrsOperation = new CdmOperationRenameAttributes(ctx)
            {
                RenameFormat = renameFormat
            };

            projection.Operations.Add(renameAttrsOperation);

            if (countAttName != null)
            {
                var countAttribute = new CdmTypeAttributeDefinition(ctx, countAttName)
                {
                    DataType = new CdmDataTypeReference(ctx, "integer", true)
                };

                // Link for the AddCountAttribute operation documentation.
                // https://docs.microsoft.com/en-us/common-data-model/sdk/projections/addcountattribute
                // It is recommended, but not mandated, to be used with the ArrayExpansion operation to provide an ArrayExpansion a count attribute that
                // represents the total number of expanded elements. AddCountAttribute can also be used by itself.
                var addCountAttrOperation = new CdmOperationAddCountAttribute(ctx)
                {
                    CountAttribute = countAttribute
                };
                projection.Operations.Add(addCountAttrOperation);
            }
        }
예제 #6
0
        public static OperationRenameAttributes ToData(CdmOperationRenameAttributes instance, ResolveOptions resOpt, CopyOptions options)
        {
            if (instance == null)
            {
                return(null);
            }

            OperationRenameAttributes obj = OperationBasePersistence.ToData <OperationRenameAttributes>(instance, resOpt, options);

            obj.RenameFormat = instance.RenameFormat;
            obj.ApplyTo      = instance.ApplyTo;

            return(obj);
        }
        /// <summary>
        /// Applies the arrayExpansion operation to the entity attribute provided.
        /// It also takes care of applying a renameAttributes operation and optionally applying a addCountAttribute operation.
        /// </summary>
        /// <param name="entityAttr"></param>
        /// <param name="startOrdinal"></param>
        /// <param name="endOrdinal"></param>
        /// <param name="renameFormat"></param>
        /// <param name="countAttName"></param>
        static void ApplyArrayExpansion(CdmEntityAttributeDefinition entityAttr, int startOrdinal, int endOrdinal, string renameFormat, string countAttName)
        {
            var           ctx        = entityAttr.Ctx;
            CdmProjection projection = new CdmProjection(ctx)
            {
                Source          = entityAttr.Entity,
                RunSequentially = true,
                // Link for the Condition property documentation.
                // https://docs.microsoft.com/en-us/common-data-model/sdk/convert-logical-entities-resolved-entities#condition
                Condition = "!normalized"
            };

            entityAttr.Entity = new CdmEntityReference(ctx, projection, false);

            // Link for the ArrayExpansion operation documentation.
            // https://docs.microsoft.com/en-us/common-data-model/sdk/projections/arrayexpansion
            var arrExpansionOperation = new CdmOperationArrayExpansion(ctx)
            {
                StartOrdinal = startOrdinal,
                EndOrdinal   = endOrdinal
            };

            projection.Operations.Add(arrExpansionOperation);

            // Link for the RenameAttributes operation documentation.
            // https://docs.microsoft.com/en-us/common-data-model/sdk/projections/renameattributes
            var renameAttrsOperation = new CdmOperationRenameAttributes(ctx)
            {
                RenameFormat = renameFormat
            };

            projection.Operations.Add(renameAttrsOperation);

            if (countAttName != null)
            {
                var countAttribute = new CdmTypeAttributeDefinition(ctx, countAttName)
                {
                    DataType = new CdmDataTypeReference(ctx, "integer", true)
                };

                // Link for the AddCountAttribute operation documentation.
                // https://docs.microsoft.com/en-us/common-data-model/sdk/projections/addcountattribute
                var addCountAttrOperation = new CdmOperationAddCountAttribute(ctx)
                {
                    CountAttribute = countAttribute
                };
                projection.Operations.Add(addCountAttrOperation);
            }
        }
예제 #8
0
        public static OperationRenameAttributes ToData(CdmOperationRenameAttributes instance, ResolveOptions resOpt, CopyOptions options)
        {
            if (instance == null)
            {
                return(null);
            }

            return(new OperationRenameAttributes
            {
                Type = OperationTypeConvertor.OperationTypeToString(CdmOperationType.RenameAttributes),
                Explanation = instance.Explanation,
                RenameFormat = instance.RenameFormat,
                ApplyTo = instance.ApplyTo
            });
        }
예제 #9
0
        public static CdmOperationRenameAttributes FromData(CdmCorpusContext ctx, JToken obj)
        {
            if (obj == null)
            {
                return(null);
            }

            CdmOperationRenameAttributes renameAttributesOp = ctx.Corpus.MakeObject <CdmOperationRenameAttributes>(CdmObjectType.OperationRenameAttributesDef);


            if (obj["$type"] != null && !StringUtils.EqualsWithIgnoreCase(obj["$type"].ToString(), OperationTypeConvertor.OperationTypeToString(CdmOperationType.RenameAttributes)))
            {
                Logger.Error(nameof(OperationRenameAttributesPersistence), ctx, $"$type {obj["$type"].ToString()} is invalid for this operation.");
            }
            else
            {
                renameAttributesOp.Type = CdmOperationType.RenameAttributes;
            }
            if (obj["explanation"] != null)
            {
                renameAttributesOp.Explanation = (string)obj["explanation"];
            }
            renameAttributesOp.RenameFormat = obj["renameFormat"]?.ToString();

            if (obj["applyTo"] is JValue)
            {
                renameAttributesOp.ApplyTo = new List <string>
                {
                    (string)obj["applyTo"]
                };
            }
            else if (obj["applyTo"] is JArray applyToArray)
            {
                renameAttributesOp.ApplyTo = applyToArray.ToObject <List <string> >();
            }
            else if (obj["applyTo"] != null)
            {
                Logger.Error(nameof(OperationRenameAttributesPersistence), ctx, "Unsupported: applyTo property type should be string or List<string>.");
                return(null);
            }

            return(renameAttributesOp);
        }
예제 #10
0
        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 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);

            // 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 projections
            // Original set of attributes: ["id", "name", "value", "date"]
            // Expand 1...2, renameFormat = {m}{o}
            Assert.AreEqual(8, resolvedEntityWithReferenceOnly.Attributes.Count);
            Assert.AreEqual("id1", (resolvedEntityWithReferenceOnly.Attributes[0] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("name1", (resolvedEntityWithReferenceOnly.Attributes[1] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("value1", (resolvedEntityWithReferenceOnly.Attributes[2] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("date1", (resolvedEntityWithReferenceOnly.Attributes[3] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("id2", (resolvedEntityWithReferenceOnly.Attributes[4] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("name2", (resolvedEntityWithReferenceOnly.Attributes[5] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("value2", (resolvedEntityWithReferenceOnly.Attributes[6] as CdmTypeAttributeDefinition).Name);
            Assert.AreEqual("date2", (resolvedEntityWithReferenceOnly.Attributes[7] as CdmTypeAttributeDefinition).Name);

            // Now resolve the entity with the default directives
            resOpt.Directives = new AttributeResolutionDirectiveSet(new HashSet <string> {
            });
            CdmEntityDefinition resolvedEntityWithStructured = await entity.CreateResolvedEntityAsync($"Resolved_{entity.EntityName}.cdm.json", resOpt, 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(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);
        }
예제 #11
0
        public static CdmProjection FromData(CdmCorpusContext ctx, JToken obj)
        {
            if (obj == null)
            {
                return(null);
            }

            CdmProjection projection = ctx.Corpus.MakeObject <CdmProjection>(CdmObjectType.ProjectionDef);

            CdmEntityReference source = EntityReferencePersistence.FromData(ctx, obj["source"]);

            if (obj["explanation"] != null)
            {
                projection.Explanation = (string)obj["explanation"];
            }

            projection.Condition       = obj["condition"]?.ToString();
            projection.RunSequentially = (bool?)obj["runSequentially"];

            if (obj["operations"] != null)
            {
                List <JObject> operationJsons = obj["operations"]?.ToObject <List <JObject> >();
                foreach (JObject operationJson in operationJsons)
                {
                    string type = (string)operationJson["$type"];
                    switch (type)
                    {
                    case "addCountAttribute":
                        CdmOperationAddCountAttribute addCountAttributeOp = OperationAddCountAttributePersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(addCountAttributeOp);
                        break;

                    case "addSupportingAttribute":
                        CdmOperationAddSupportingAttribute addSupportingAttributeOp = OperationAddSupportingAttributePersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(addSupportingAttributeOp);
                        break;

                    case "addTypeAttribute":
                        CdmOperationAddTypeAttribute addTypeAttributeOp = OperationAddTypeAttributePersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(addTypeAttributeOp);
                        break;

                    case "excludeAttributes":
                        CdmOperationExcludeAttributes excludeAttributesOp = OperationExcludeAttributesPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(excludeAttributesOp);
                        break;

                    case "arrayExpansion":
                        CdmOperationArrayExpansion arrayExpansionOp = OperationArrayExpansionPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(arrayExpansionOp);
                        break;

                    case "combineAttributes":
                        CdmOperationCombineAttributes combineAttributesOp = OperationCombineAttributesPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(combineAttributesOp);
                        break;

                    case "renameAttributes":
                        CdmOperationRenameAttributes renameAttributesOp = OperationRenameAttributesPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(renameAttributesOp);
                        break;

                    case "replaceAsForeignKey":
                        CdmOperationReplaceAsForeignKey replaceAsForeignKeyOp = OperationReplaceAsForeignKeyPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(replaceAsForeignKeyOp);
                        break;

                    case "includeAttributes":
                        CdmOperationIncludeAttributes includeAttributesOp = OperationIncludeAttributesPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(includeAttributesOp);
                        break;

                    case "addAttributeGroup":
                        CdmOperationAddAttributeGroup addAttributeGroupOp = OperationAddAttributeGroupPersistence.FromData(ctx, operationJson);
                        projection.Operations.Add(addAttributeGroupOp);
                        break;

                    default:
                        Logger.Error(nameof(ProjectionPersistence), ctx, $"Invalid operation type '{type}'.", nameof(FromData));
                        break;
                    }
                }
            }

            projection.Source = source;

            return(projection);
        }
예제 #12
0
        /// <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);
        }