示例#1
0
        private static string MapEnumToTypeName(CdmAttributeContextType enumVal)
        {
            switch (enumVal)
            {
            case CdmAttributeContextType.Entity:
                return("entity");

            case CdmAttributeContextType.EntityReferenceExtends:
                return("entityReferenceExtends");

            case CdmAttributeContextType.AttributeGroup:
                return("attributeGroup");

            case CdmAttributeContextType.AttributeDefinition:
                return("attributeDefinition");

            case CdmAttributeContextType.AddedAttributeSupporting:
                return("addedAttributeSupporting");

            case CdmAttributeContextType.AddedAttributeIdentity:
                return("addedAttributeIdentity");

            case CdmAttributeContextType.AddedAttributeExpansionTotal:
                return("addedAttributeExpansionTotal");

            case CdmAttributeContextType.AddedAttributeSelectedType:
                return("addedAttributeSelectedType");

            case CdmAttributeContextType.GeneratedRound:
                return("generatedRound");

            case CdmAttributeContextType.GeneratedSet:
                return("generatedSet");

            default:
                return("unknown");
            }
        }
        private static string MapEnumToTypeName(CdmAttributeContextType enumVal)
        {
            switch (enumVal)
            {
            case CdmAttributeContextType.Entity:
                return("entity");

            case CdmAttributeContextType.EntityReferenceExtends:
                return("entityReferenceExtends");

            case CdmAttributeContextType.AttributeGroup:
                return("attributeGroup");

            case CdmAttributeContextType.AttributeDefinition:
                return("attributeDefinition");

            case CdmAttributeContextType.AddedAttributeSupporting:
                return("addedAttributeSupporting");

            case CdmAttributeContextType.AddedAttributeIdentity:
                return("addedAttributeIdentity");

            case CdmAttributeContextType.AddedAttributeExpansionTotal:
                return("addedAttributeExpansionTotal");

            case CdmAttributeContextType.AddedAttributeSelectedType:
                return("addedAttributeSelectedType");

            case CdmAttributeContextType.GeneratedRound:
                return("generatedRound");

            case CdmAttributeContextType.GeneratedSet:
                return("generatedSet");

            case CdmAttributeContextType.Projection:
                return("projection");

            case CdmAttributeContextType.Source:
                return("source");

            case CdmAttributeContextType.Operations:
                return("operations");

            case CdmAttributeContextType.OperationAddCountAttribute:
                return("operationAddCountAttribute");

            case CdmAttributeContextType.OperationAddSupportingAttribute:
                return("operationAddSupportingAttribute");

            case CdmAttributeContextType.OperationAddTypeAttribute:
                return("operationAddTypeAttribute");

            case CdmAttributeContextType.OperationExcludeAttributes:
                return("operationExcludeAttributes");

            case CdmAttributeContextType.OperationArrayExpansion:
                return("operationArrayExpansion");

            case CdmAttributeContextType.OperationCombineAttributes:
                return("operationCombineAttributes");

            case CdmAttributeContextType.OperationRenameAttributes:
                return("operationRenameAttributes");

            case CdmAttributeContextType.OperationReplaceAsForeignKey:
                return("operationReplaceAsForeignKey");

            case CdmAttributeContextType.OperationIncludeAttributes:
                return("operationIncludeAttributes");

            case CdmAttributeContextType.OperationAddAttributeGroup:
                return("operationAddAttributeGroup");

            default:
                return("unknown");
            }
        }
示例#3
0
        /// <summary>
        /// Creates the attribute context parameters for the searchFor, found, and action nodes and then stores them in different maps.
        /// The maps are used when constructing the actual attribute context tree.
        /// </summary>
        /// <param name="searchFor">The "search for" string</param>
        /// <param name="found">The projection attribute state that contains the "found" attribute</param>
        /// <param name="resAttrFromAction">The resolved attribute that resulted from the action</param>
        /// <param name="attrCtxType">The attribute context type to give the "action" attribute context parameter</param>
        internal void CreateAndStoreAttributeContextParameters(string searchFor, ProjectionAttributeState found, ResolvedAttribute resAttrFromAction, CdmAttributeContextType attrCtxType)
        {
            // searchFor is null when we have to construct attribute contexts for the excluded attributes in Include or the included attributes in Exclude,
            // as these attributes weren't searched for with a searchFor name.
            // If searchFor is null, just set it to have the same name as found so that it'll collapse in the final tree.
            if (searchFor == null)
            {
                searchFor = found.CurrentResolvedAttribute.ResolvedName;
            }

            // Create the attribute context parameter for the searchFor node and store it in the map as [searchFor name]:[attribute context parameter]
            AttributeContextParameters searchForAttrCtxParam = null;

            if (!searchForToSearchForAttrCtxParam.ContainsKey(searchFor))
            {
                searchForAttrCtxParam = new AttributeContextParameters
                {
                    under = root,
                    type  = CdmAttributeContextType.AttributeDefinition,
                    Name  = searchFor
                };

                searchForToSearchForAttrCtxParam.Add(searchFor, searchForAttrCtxParam);
            }
            else
            {
                searchForToSearchForAttrCtxParam.TryGetValue(searchFor, out searchForAttrCtxParam);
            }

            // Create the attribute context parameter for the found node
            AttributeContextParameters foundAttrCtxParam = new AttributeContextParameters
            {
                under = root, // Set this to be under the root for now, as we may end up collapsing this node
                type  = CdmAttributeContextType.AttributeDefinition,
                Name  = $"{found.CurrentResolvedAttribute.ResolvedName}{(found.Ordinal != null ? "@" + found.Ordinal : "")}"
            };

            // Store this in the map as [searchFor attribute context parameter]:[found attribute context parameters]
            // We store it this way so that we can create the found nodes under their corresponding searchFor nodes.
            if (!searchForAttrCtxParamToFoundAttrCtxParam.ContainsKey(searchForAttrCtxParam))
            {
                searchForAttrCtxParamToFoundAttrCtxParam.Add(searchForAttrCtxParam, new List <AttributeContextParameters> {
                    foundAttrCtxParam
                });
            }
            else
            {
                List <AttributeContextParameters> foundAttrCtxParams = null;
                searchForAttrCtxParamToFoundAttrCtxParam.TryGetValue(searchForAttrCtxParam, out foundAttrCtxParams);
                foundAttrCtxParams.Add(foundAttrCtxParam);
                searchForAttrCtxParamToFoundAttrCtxParam[searchForAttrCtxParam] = foundAttrCtxParams;
            }

            // Create the attribute context parameter for the action node
            AttributeContextParameters actionAttrCtxParam = new AttributeContextParameters
            {
                under = root,        // Set this to be under the root for now, as we may end up collapsing this node
                type  = attrCtxType, // This type will be updated once we implement the new attribute context types
                Name  = resAttrFromAction.ResolvedName
            };

            // Store this in the map as [found attribute context parameter]:[action attribute context parameter]
            // We store it this way so that we can create the action nodes under their corresponding found nodes.
            foundAttrCtxParamToActionAttrCtxParam[foundAttrCtxParam] = actionAttrCtxParam;

            // Store the action attribute context parameter with the resolved attribute resulting out of the action.
            // This is so that we can point the action attribute context to the correct resolved attribute once the attribute context is created.
            actionAttrCtxParamToResAttr[actionAttrCtxParam] = resAttrFromAction;
        }
        internal override ResolvedAttributeSetBuilder ConstructResolvedAttributes(ResolveOptions resOpt, CdmAttributeContext under = null)
        {
            // find and cache the complete set of attributes
            // attributes definitions originate from and then get modified by subsequent re-defintions from (in this order):
            // the entity used as an attribute, traits applied to that entity,
            // the purpose of the attribute, any traits applied to the attribute.
            ResolvedAttributeSetBuilder rasb     = new ResolvedAttributeSetBuilder();
            CdmEntityReference          ctxEnt   = this.Entity;
            CdmAttributeContext         underAtt = under;
            AttributeContextParameters  acpEnt   = null;

            var ctxEntObjDef = ctxEnt.FetchObjectDefinition <CdmObjectDefinition>(resOpt);

            if (ctxEntObjDef.ObjectType == CdmObjectType.ProjectionDef)
            {
                // A Projection

                ProjectionDirective projDirective = new ProjectionDirective(resOpt, this, ownerRef: ctxEnt);
                CdmProjection       projDef       = (CdmProjection)ctxEntObjDef;
                ProjectionContext   projCtx       = projDef.ConstructProjectionContext(projDirective, under);

                ResolvedAttributeSet ras = projDef.ExtractResolvedAttributes(projCtx);
                rasb.ResolvedAttributeSet = ras;
            }
            else
            {
                // An Entity Reference

                if (underAtt != null)
                {
                    // make a context for this attreibute that holds the attributes that come up from the entity
                    acpEnt = new AttributeContextParameters
                    {
                        under         = underAtt,
                        type          = CdmAttributeContextType.Entity,
                        Name          = ctxEnt.FetchObjectDefinitionName(),
                        Regarding     = ctxEnt,
                        IncludeTraits = true
                    };
                }

                ResolvedTraitSet rtsThisAtt = this.FetchResolvedTraits(resOpt);

                // this context object holds all of the info about what needs to happen to resolve these attributes.
                // make a copy and add defaults if missing
                CdmAttributeResolutionGuidance resGuideWithDefault;
                if (this.ResolutionGuidance != null)
                {
                    resGuideWithDefault = (CdmAttributeResolutionGuidance)this.ResolutionGuidance.Copy(resOpt);
                }
                else
                {
                    resGuideWithDefault = new CdmAttributeResolutionGuidance(this.Ctx);
                }
                resGuideWithDefault.UpdateAttributeDefaults(this.Name);

                AttributeResolutionContext arc = new AttributeResolutionContext(resOpt, resGuideWithDefault, rtsThisAtt);

                // complete cheating but is faster.
                // this purpose will remove all of the attributes that get collected here, so dumb and slow to go get them
                RelationshipInfo relInfo = this.GetRelationshipInfo(arc.ResOpt, arc);
                if (relInfo.IsByRef)
                {
                    // make the entity context that a real recursion would have give us
                    if (under != null)
                    {
                        under = rasb.ResolvedAttributeSet.CreateAttributeContext(resOpt, acpEnt);
                    }
                    // if selecting from one of many attributes, then make a context for each one
                    if (under != null && relInfo.SelectsOne)
                    {
                        // the right way to do this is to get a resolved entity from the embedded entity and then
                        // look through the attribute context hierarchy for non-nested entityReferenceAsAttribute nodes
                        // that seems like a disaster waiting to happen given endless looping, etc.
                        // for now, just insist that only the top level entity attributes declared in the ref entity will work
                        CdmEntityDefinition entPickFrom           = (this.Entity as CdmEntityReference).FetchObjectDefinition <CdmEntityDefinition>(resOpt) as CdmEntityDefinition;
                        CdmCollection <CdmAttributeItem> attsPick = entPickFrom?.Attributes;
                        if (entPickFrom != null && attsPick != null)
                        {
                            for (int i = 0; i < attsPick.Count; i++)
                            {
                                if (attsPick.AllItems[i].ObjectType == CdmObjectType.EntityAttributeDef)
                                {
                                    // a table within a table. as expected with a selectsOne attribute
                                    // since this is by ref, we won't get the atts from the table, but we do need the traits that hold the key
                                    // these are the same contexts that would get created if we recursed
                                    // first this attribute
                                    AttributeContextParameters acpEntAtt = new AttributeContextParameters
                                    {
                                        under         = under,
                                        type          = CdmAttributeContextType.AttributeDefinition,
                                        Name          = attsPick.AllItems[i].FetchObjectDefinitionName(),
                                        Regarding     = attsPick.AllItems[i],
                                        IncludeTraits = true
                                    };
                                    CdmAttributeContext     pickUnder   = rasb.ResolvedAttributeSet.CreateAttributeContext(resOpt, acpEntAtt);
                                    CdmEntityReference      pickEnt     = (attsPick.AllItems[i] as CdmEntityAttributeDefinition).Entity as CdmEntityReference;
                                    CdmAttributeContextType pickEntType = (pickEnt.FetchObjectDefinition <CdmObjectDefinition>(resOpt).ObjectType == CdmObjectType.ProjectionDef) ?
                                                                          CdmAttributeContextType.Projection :
                                                                          CdmAttributeContextType.Entity;
                                    AttributeContextParameters acpEntAttEnt = new AttributeContextParameters
                                    {
                                        under         = pickUnder,
                                        type          = pickEntType,
                                        Name          = pickEnt.FetchObjectDefinitionName(),
                                        Regarding     = pickEnt,
                                        IncludeTraits = true
                                    };
                                    rasb.ResolvedAttributeSet.CreateAttributeContext(resOpt, acpEntAttEnt);
                                }
                            }
                        }
                    }

                    // if we got here because of the max depth, need to impose the directives to make the trait work as expected
                    if (relInfo.MaxDepthExceeded)
                    {
                        if (arc.ResOpt.Directives == null)
                        {
                            arc.ResOpt.Directives = new AttributeResolutionDirectiveSet();
                        }
                        arc.ResOpt.Directives.Add("referenceOnly");
                    }
                }
                else
                {
                    ResolveOptions resLink = CopyResolveOptions(resOpt);
                    resLink.SymbolRefSet      = resOpt.SymbolRefSet;
                    resLink.RelationshipDepth = relInfo.NextDepth;
                    rasb.MergeAttributes(this.Entity.FetchResolvedAttributes(resLink, acpEnt));
                }

                // from the traits of purpose and applied here, see if new attributes get generated
                rasb.ResolvedAttributeSet.AttributeContext = underAtt;
                rasb.ApplyTraits(arc);
                rasb.GenerateApplierAttributes(arc, true); // true = apply the prepared traits to new atts
                                                           // this may have added symbols to the dependencies, so merge them
                resOpt.SymbolRefSet.Merge(arc.ResOpt.SymbolRefSet);

                // use the traits for linked entity identifiers to record the actual foreign key links
                if (rasb.ResolvedAttributeSet?.Set != null && relInfo.IsByRef)
                {
                    foreach (var att in rasb.ResolvedAttributeSet.Set)
                    {
                        if (att.ResolvedTraits != null)
                        {
                            var reqdTrait = att.ResolvedTraits.Find(resOpt, "is.linkedEntity.identifier");
                            if (reqdTrait == null)
                            {
                                continue;
                            }

                            if (reqdTrait.ParameterValues == null || reqdTrait.ParameterValues.Length == 0)
                            {
                                Logger.Warning(nameof(CdmEntityAttributeDefinition), this.Ctx as ResolveContext, "is.linkedEntity.identifier does not support arguments");
                                continue;
                            }

                            var entReferences = new List <string>();
                            var attReferences = new List <string>();
                            Action <CdmEntityReference, string> addEntityReference = (CdmEntityReference entRef, string nameSpace) =>
                            {
                                var entDef = entRef.FetchObjectDefinition <CdmEntityDefinition>(resOpt);
                                if (entDef != null)
                                {
                                    var           otherResTraits = entRef.FetchResolvedTraits(resOpt);
                                    ResolvedTrait identifyingTrait;
                                    if (otherResTraits != null && (identifyingTrait = otherResTraits.Find(resOpt, "is.identifiedBy")) != null)
                                    {
                                        var    attRef          = identifyingTrait.ParameterValues.FetchParameterValueByName("attribute").Value;
                                        string attNamePath     = ((CdmObjectReferenceBase)attRef).NamedReference;
                                        string attName         = attNamePath.Split('/').Last();                        // path should be absolute and without a namespace
                                        string relativeEntPath = Ctx.Corpus.Storage.CreateAbsoluteCorpusPath(entDef.AtCorpusPath, entDef.InDocument);
                                        if (relativeEntPath.StartsWith($"{nameSpace}:"))
                                        {
                                            relativeEntPath = relativeEntPath.Substring(nameSpace.Length + 1);
                                        }
                                        entReferences.Add(relativeEntPath);
                                        attReferences.Add(attName);
                                    }
                                }
                            };
                            if (relInfo.SelectsOne)
                            {
                                var entPickFrom = (this.Entity as CdmEntityReference).FetchObjectDefinition <CdmEntityDefinition>(resOpt) as CdmEntityDefinition;
                                var attsPick    = entPickFrom?.Attributes.Cast <CdmObject>().ToList();
                                if (entPickFrom != null && attsPick != null)
                                {
                                    for (int i = 0; i < attsPick.Count; i++)
                                    {
                                        if (attsPick[i].ObjectType == CdmObjectType.EntityAttributeDef)
                                        {
                                            var entAtt = attsPick[i] as CdmEntityAttributeDefinition;
                                            addEntityReference(entAtt.Entity, this.InDocument.Namespace);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                addEntityReference(this.Entity, this.InDocument.Namespace);
                            }

                            var constantEntity = this.Ctx.Corpus.MakeObject <CdmConstantEntityDefinition>(CdmObjectType.ConstantEntityDef);
                            constantEntity.EntityShape    = this.Ctx.Corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, "entityGroupSet", true);
                            constantEntity.ConstantValues = entReferences.Select((entRef, idx) => new List <string> {
                                entRef, attReferences[idx]
                            }).ToList();
                            var traitParam = this.Ctx.Corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, constantEntity, false);
                            reqdTrait.ParameterValues.SetParameterValue(resOpt, "entityReferences", traitParam);
                        }
                    }
                }

                // a 'structured' directive wants to keep all entity attributes together in a group
                if (arc.ResOpt.Directives?.Has("structured") == true)
                {
                    ResolvedAttribute raSub = new ResolvedAttribute(rtsThisAtt.ResOpt, rasb.ResolvedAttributeSet, this.Name, rasb.ResolvedAttributeSet.AttributeContext);
                    if (relInfo.IsArray)
                    {
                        // put a resolved trait on this att group, yuck, hope I never need to do this again and then need to make a function for this
                        CdmTraitReference tr = this.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, "is.linkedEntity.array", true);
                        var           t      = tr.FetchObjectDefinition <CdmTraitDefinition>(resOpt);
                        ResolvedTrait rt     = new ResolvedTrait(t, null, new List <dynamic>(), new List <bool>());
                        raSub.ResolvedTraits = raSub.ResolvedTraits.Merge(rt, true);
                    }
                    rasb = new ResolvedAttributeSetBuilder();
                    rasb.ResolvedAttributeSet.AttributeContext = raSub.AttCtx; // this got set to null with the new builder
                    rasb.OwnOne(raSub);
                }
            }

            return(rasb);
        }
        /// <summary>
        /// Creates the attribute context parameters for the searchFor, found, and action nodes and then stores them in different maps.
        /// The maps are used when constructing the actual attribute context tree.
        /// </summary>
        /// <param name="searchFor">The "search for" string</param>
        /// <param name="found">The projection attribute state that contains the "found" attribute</param>
        /// <param name="resAttrFromAction">The resolved attribute that resulted from the action</param>
        /// <param name="attrCtxType">The attribute context type to give the "action" attribute context parameter</param>
        /// <param name="lineageOut">normally lineage goes from new context to the found. false means don't and maybe even flip it</param>
        /// <param name="lineageIn"></param>
        internal void CreateAndStoreAttributeContextParameters(string searchFor, ProjectionAttributeState found, ResolvedAttribute resAttrFromAction,
                                                               CdmAttributeContextType attrCtxType, CdmAttributeContext lineageOut, CdmAttributeContext lineageIn)
        {
            // searchFor is null when we have to construct attribute contexts for the excluded attributes in Include or the included attributes in Exclude,
            // as these attributes weren't searched for with a searchFor name.
            // If searchFor is null, just set it to have the same name as found so that it'll collapse in the final tree.
            if (searchFor == null)
            {
                searchFor = found.CurrentResolvedAttribute.ResolvedName;
            }

            // Create the attribute context parameter for the searchFor node and store it in the map as [searchFor name]:[attribute context parameter]
            AttributeContextParameters searchForAttrCtxParam = null;

            if (!searchForToSearchForAttrCtxParam.ContainsKey(searchFor))
            {
                searchForAttrCtxParam = new AttributeContextParameters
                {
                    under = root,
                    type  = CdmAttributeContextType.AttributeDefinition,
                    Name  = searchFor
                };

                searchForToSearchForAttrCtxParam.Add(searchFor, searchForAttrCtxParam);
            }
            else
            {
                searchForToSearchForAttrCtxParam.TryGetValue(searchFor, out searchForAttrCtxParam);
            }

            // Create the attribute context parameter for the found node
            AttributeContextParameters foundAttrCtxParam = new AttributeContextParameters
            {
                under = root, // Set this to be under the root for now, as we may end up collapsing this node
                type  = CdmAttributeContextType.AttributeDefinition,
                Name  = $"{found.CurrentResolvedAttribute.ResolvedName}{(found.Ordinal != null ? "@" + found.Ordinal : "")}"
            };

            // Store this in the map as [searchFor attribute context parameter]:[found attribute context parameters]
            // We store it this way so that we can create the found nodes under their corresponding searchFor nodes.
            if (!searchForAttrCtxParamToFoundAttrCtxParam.ContainsKey(searchForAttrCtxParam))
            {
                searchForAttrCtxParamToFoundAttrCtxParam.Add(searchForAttrCtxParam, new List <AttributeContextParameters>());
            }

            List <AttributeContextParameters> foundAttrCtxParams = searchForAttrCtxParamToFoundAttrCtxParam[searchForAttrCtxParam];

            foundAttrCtxParams.Add(foundAttrCtxParam);

            // Create the attribute context parameter for the action node
            AttributeContextParameters actionAttrCtxParam = new AttributeContextParameters
            {
                under = root,        // Set this to be under the root for now, as we may end up collapsing this node
                type  = attrCtxType, // This type will be updated once we implement the new attribute context types
                Name  = resAttrFromAction.ResolvedName
            };

            // Store this in the map as [found attribute context parameter]:[action attribute context parameter]
            // We store it this way so that we can create the action nodes under their corresponding found nodes.
            foundAttrCtxParamToActionAttrCtxParam[foundAttrCtxParam] = actionAttrCtxParam;

            // Store the action attribute context parameter with the resolved attribute resulting out of the action.
            // This is so that we can point the action attribute context to the correct resolved attribute once the attribute context is created.
            actionAttrCtxParamToResAttr[actionAttrCtxParam] = resAttrFromAction;

            // store the current resAtt as the lineage of the new one
            // of note, if no lineage is stored AND the resolved Att associated above holds an existing context? we will
            // flip the lineage when we make a new context and point 'back' to this new node. this means this new node should
            // point 'back' to the context of the source attribute
            if (lineageOut != null)
            {
                actionAttrCtxParamToLineageOut[actionAttrCtxParam] = lineageOut;
            }
            if (lineageIn != null)
            {
                actionAttrCtxParamToLineageIn[actionAttrCtxParam] = lineageIn;
            }
        }