/// <summary> /// Projections require a new resolved attribute to be created multiple times /// This function allows us to create new resolved attributes based on a input attribute /// </summary> /// <param name="projCtx"></param> /// <param name="attrCtxUnder"></param> /// <param name="oldResolvedAttribute"> /// For some attributes obtained from the previous projection operation, they may have a different set of traits comparing to the resolved attribute target. /// We would want to take the set of traits from the resolved attribute. /// </param> /// <param name="overrideDefaultName"></param> /// <param name="addedSimpleRefTraits"></param> /// <returns></returns> internal static ResolvedAttribute CreateNewResolvedAttribute( ProjectionContext projCtx, CdmAttributeContext attrCtxUnder, ResolvedAttribute oldResolvedAttribute, string overrideDefaultName = null, List <string> addedSimpleRefTraits = null) { var targetAttr = oldResolvedAttribute.Target.Copy() as CdmAttribute; ResolvedAttribute newResAttr = new ResolvedAttribute( projCtx.ProjectionDirective.ResOpt, targetAttr, !string.IsNullOrWhiteSpace(overrideDefaultName) ? overrideDefaultName : targetAttr.GetName(), attrCtxUnder); targetAttr.InDocument = projCtx.ProjectionDirective.Owner.InDocument; newResAttr.ResolvedTraits = oldResolvedAttribute.ResolvedTraits.DeepCopy(); if (addedSimpleRefTraits != null) { foreach (string trait in addedSimpleRefTraits) { var tr = new CdmTraitReference(targetAttr.Ctx, trait, true, false); newResAttr.ResolvedTraits = newResAttr.ResolvedTraits.MergeSet(tr.FetchResolvedTraits()); } } return(newResAttr); }
internal override CdmObjectReferenceBase CopyRefObject(ResolveOptions resOpt, dynamic refTo, bool simpleReference, CdmObjectReferenceBase host = null) { CdmTraitReference copy; if (host == null) { copy = new CdmTraitReference(this.Ctx, refTo, simpleReference, this.Arguments?.Count > 0); } else { copy = host.CopyToHost(this.Ctx, refTo, simpleReference); copy.Arguments.Clear(); } if (!simpleReference) { copy.ResolvedArguments = this.ResolvedArguments; } foreach (var arg in this.Arguments) { copy.Arguments.Add(arg); } return(copy); }
/// <summary> /// Constructs a CdmTraitDefinition. /// </summary> /// <param name="ctx">The context.</param> /// <param name="name">The trait name.</param> /// <param name="extendsTrait">The trait extended by this trait.</param> public CdmTraitDefinition(CdmCorpusContext ctx, string name, CdmTraitReference extendsTrait = null) : base(ctx) { this.HasSetFlags = false; this.ObjectType = CdmObjectType.TraitDef; this.TraitName = name; this.ExtendsTrait = extendsTrait; }
/// <inheritdoc /> internal override ProjectionAttributeStateSet AppendProjectionAttributeState( ProjectionContext projCtx, ProjectionAttributeStateSet projOutputSet, CdmAttributeContext attrCtx) { // Pass through all the input projection attribute states if there are any foreach (ProjectionAttributeState currentPAS in projCtx.CurrentAttributeStateSet.States) { projOutputSet.Add(currentPAS); } // Create a new attribute context for the operation AttributeContextParameters attrCtxOpAddSupportingAttrParam = new AttributeContextParameters { under = attrCtx, type = CdmAttributeContextType.OperationAddSupportingAttribute, Name = $"operation/index{Index}/{this.GetName()}" }; CdmAttributeContext attrCtxOpAddSupportingAttr = CdmAttributeContext.CreateChildUnder(projCtx.ProjectionDirective.ResOpt, attrCtxOpAddSupportingAttrParam); // Create a new attribute context for the supporting attribute we will create AttributeContextParameters attrCtxTypeAttrParam = new AttributeContextParameters { under = attrCtxOpAddSupportingAttr, type = CdmAttributeContextType.AddedAttributeSupporting, Name = this.SupportingAttribute.Name }; CdmAttributeContext attrCtxSupportingAttr = CdmAttributeContext.CreateChildUnder(projCtx.ProjectionDirective.ResOpt, attrCtxTypeAttrParam); // TODO: this if statement keeps the functionality the same way it works currently in resolution guidance. // This should be changed to point to the foreign key attribute instead. // There has to be some design decisions about how this will work and will be done in the next release. if (projCtx.CurrentAttributeStateSet.States.Count > 0) { ProjectionAttributeState lastState = projCtx.CurrentAttributeStateSet.States[projCtx.CurrentAttributeStateSet.States.Count - 1]; CdmTraitReference inSupportOfTrait = this.SupportingAttribute.AppliedTraits.Add("is.addedInSupportOf"); inSupportOfTrait.Arguments.Add("inSupportOf", lastState.CurrentResolvedAttribute.ResolvedName); } // Create the supporting attribute with the specified "SupportingAttribute" property as its target and apply the trait "is.virtual.attribute" to it List <string> addTrait = new List <string>() { "is.virtual.attribute" }; ResolvedAttribute newResAttr = CreateNewResolvedAttribute(projCtx, attrCtxSupportingAttr, this.SupportingAttribute, addedSimpleRefTraits: addTrait); // Create a new projection attribute state for the new supporting attribute and add it to the output set // There is no previous state for the newly created supporting attribute ProjectionAttributeState newPAS = new ProjectionAttributeState(projOutputSet.Ctx) { CurrentResolvedAttribute = newResAttr }; projOutputSet.Add(newPAS); return(projOutputSet); }
/// <summary> /// Determine if calling FileStatusCheckAsync on the given pattern or the given partition is needed. /// </summary> /// <param name="incrementalType">The incremental type.</param> /// <param name="isPattern">Whether the object is a pattern object or a partition object.</param> /// <param name="patternOrPartitionObj">The pattern object if isPattern is true, otherwise the partition object.</param> private bool ShouldCallFileStatusCheck(CdmIncrementalPartitionType incrementalType, bool isPattern, CdmObjectDefinitionBase patternOrPartitionObj) { var update = true; CdmTraitReference traitRef = patternOrPartitionObj.ExhibitsTraits.Item(Constants.IncrementalTraitName) as CdmTraitReference; if (traitRef == null) { Logger.Error(patternOrPartitionObj.Ctx, Tag, nameof(ShouldCallFileStatusCheck), patternOrPartitionObj.AtCorpusPath, CdmLogCode.ErrMissingIncrementalPartitionTrait, isPattern ? nameof(CdmDataPartitionPatternDefinition) : nameof(CdmDataPartitionDefinition), patternOrPartitionObj.FetchObjectDefinitionName(), Constants.IncrementalTraitName, isPattern ? nameof(IncrementalPartitionPatterns) : nameof(IncrementalPartitions)); } else { // None means update by default if (incrementalType == CdmIncrementalPartitionType.None) { return(update); } var traitRefIncrementalTypeValue = traitRef.Arguments?.FetchValue("type"); if (traitRefIncrementalTypeValue == null) { update = false; Logger.Error(patternOrPartitionObj.Ctx, Tag, nameof(ShouldCallFileStatusCheck), patternOrPartitionObj.AtCorpusPath, CdmLogCode.ErrTraitArgumentMissing, "type", Constants.IncrementalTraitName, patternOrPartitionObj.FetchObjectDefinitionName()); } else if (traitRefIncrementalTypeValue is string == false) { update = false; Logger.Error(patternOrPartitionObj.Ctx, Tag, nameof(ShouldCallFileStatusCheck), patternOrPartitionObj.AtCorpusPath, CdmLogCode.ErrTraitInvalidArgumentValueType, "type", Constants.IncrementalTraitName, patternOrPartitionObj.FetchObjectDefinitionName()); } else { bool success = Enum.TryParse(traitRefIncrementalTypeValue.ToString(), out CdmIncrementalPartitionType traitRefIncrementalType); if (success) { update = traitRefIncrementalType == incrementalType; } else { update = false; Logger.Error(patternOrPartitionObj.Ctx, Tag, nameof(ShouldCallFileStatusCheck), patternOrPartitionObj.AtCorpusPath, CdmLogCode.ErrEnumConversionFailure, traitRefIncrementalTypeValue, nameof(CdmIncrementalPartitionType), $"parameter 'type' of trait '{Constants.IncrementalTraitName}' from '{patternOrPartitionObj.FetchObjectDefinitionName()}'"); } } } return(update); }
internal static CdmTraitReference ResolvedTraitToTraitRef(ResolveOptions resOpt, ResolvedTrait rt) { CdmTraitReference traitRef = null; if (rt.ParameterValues != null && rt.ParameterValues.Length > 0) { traitRef = rt.Trait.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, rt.TraitName, false); int l = rt.ParameterValues.Length; if (l == 1) { // just one argument, use the shortcut syntax dynamic val = ProtectParameterValues(resOpt, rt.ParameterValues.Values[0]); if (val != null) { traitRef.Arguments.Add(null, val); } } else { for (int i = 0; i < l; i++) { CdmParameterDefinition param = rt.ParameterValues.FetchParameterAtIndex(i); dynamic val = ProtectParameterValues(resOpt, rt.ParameterValues.Values[i]); if (val != null) { traitRef.Arguments.Add(param.Name, val); } } } } else { traitRef = rt.Trait.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, rt.TraitName, true); } if (resOpt.SaveResolutionsOnCopy) { // used to localize references between documents traitRef.ExplicitReference = rt.Trait; traitRef.InDocument = rt.Trait.InDocument; } // always make it a property when you can, however the dataFormat traits should be left alone // also the wellKnown is the first constrained list that uses the datatype to hold the table instead of the default value property. // so until we figure out how to move the enums away from default value, show that trait too if (rt.Trait.AssociatedProperties != null && !rt.Trait.IsDerivedFrom("is.dataFormat", resOpt) && !(rt.Trait.TraitName == "is.constrainedList.wellKnown")) { traitRef.IsFromProperty = true; } return(traitRef); }
internal static CdmTraitReference ResolvedTraitToTraitRef(ResolveOptions resOpt, ResolvedTrait rt) { CdmTraitReference traitRef = null; if (rt.ParameterValues != null && rt.ParameterValues.Length > 0) { traitRef = rt.Trait.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, rt.TraitName, false); int l = rt.ParameterValues.Length; if (l == 1) { // just one argument, use the shortcut syntax dynamic val = rt.ParameterValues.Values[0]; if (val != null) { traitRef.Arguments.Add(null, val); } } else { for (int i = 0; i < l; i++) { CdmParameterDefinition param = rt.ParameterValues.FetchParameterAtIndex(i); dynamic val = rt.ParameterValues.Values[i]; if (val != null) { traitRef.Arguments.Add(param.Name, val); } } } } else { traitRef = rt.Trait.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, rt.TraitName, true); } if (resOpt.SaveResolutionsOnCopy) { // used to localize references between documents traitRef.ExplicitReference = rt.Trait as CdmTraitDefinition; traitRef.InDocument = (rt.Trait as CdmTraitDefinition).InDocument; } // always make it a property when you can, however the dataFormat traits should be left alone if (rt.Trait.AssociatedProperties != null && !rt.Trait.IsDerivedFrom("is.dataFormat", resOpt)) { traitRef.IsFromProperty = true; } return(traitRef); }
/// <summary> /// Creates an non-simple-referenced CdmTraitReference object, assigns it the name passed as parameter, adds the supplied arguments to it if provided, and adds it to the collection. /// </summary> /// <param name="name">The name to be used for the newly created CdmTraitReference object.</param> /// <param name="args">The trait reference's arguments. This is optional, call Add(string name, bool simpleRef = false) instead if creating a simpleNameReferenced CdmTraitReference object.</param> /// <returns>The newly created object after it was added to the collection.</returns> public CdmTraitReferenceBase Add(string name, List <Tuple <string, dynamic> > args) { this.ClearCache(); CdmTraitReference traitRef = base.Add(name) as CdmTraitReference; if (traitRef == null || args == null) { return(traitRef); } foreach (Tuple <string, dynamic> tuple in args) { traitRef.Arguments.Add(tuple.Item1, tuple.Item2); } return(traitRef); }
internal static CdmTraitReference ResolvedTraitToTraitRef(ResolveOptions resOpt, ResolvedTrait rt) { CdmTraitReference traitRef = null; if (rt.ParameterValues != null && rt.ParameterValues.Length > 0) { traitRef = rt.Trait.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, rt.TraitName, false); int l = rt.ParameterValues.Length; if (l == 1) { // just one argument, use the shortcut syntax dynamic val = rt.ParameterValues.Values[0]; if (val != null) { traitRef.Arguments.Add(null, val); } } else { for (int i = 0; i < l; i++) { CdmParameterDefinition param = rt.ParameterValues.FetchParameterAtIndex(i); dynamic val = rt.ParameterValues.Values[i]; if (val != null) { traitRef.Arguments.Add(param.Name, val); } } } } else { traitRef = rt.Trait.Ctx.Corpus.MakeObject <CdmTraitReference>(CdmObjectType.TraitRef, rt.TraitName, true); } if (resOpt.SaveResolutionsOnCopy) { // used to localize references between documents traitRef.ExplicitReference = rt.Trait as CdmTraitDefinition; traitRef.DocCreatedIn = (rt.Trait as CdmTraitDefinition).DocCreatedIn; } return(traitRef); }
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 as CdmEntityReference; CdmAttributeContext underAtt = (CdmAttributeContext)under; AttributeContextParameters acpEnt = null; 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?.GetAttributeDefinitions(); 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; AttributeContextParameters acpEntAttEnt = new AttributeContextParameters { under = pickUnder, type = CdmAttributeContextType.Entity, 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 as CdmEntityReference).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) { 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); var identifyingTrait = entRef.FetchResolvedTraits(resOpt).Find(resOpt, "is.identifiedBy"); if (identifyingTrait != null && entDef != 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?.GetAttributeDefinitions()?.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, (CdmAttributeContext)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.OwnOne(raSub); } return rasb; }
/// <summary> /// Constructs a CdmArgumentCollection. /// </summary> /// <param name="ctx">The context.</param> /// <param name="owner">The owner of the collection. Has to be a <see cref="CdmTraitReference"/> because this collection is optimized to handle adjustments to the trait when adding an argument.</param> public CdmArgumentCollection(CdmCorpusContext ctx, CdmTraitReference owner) : base(ctx, owner, CdmObjectType.ArgumentDef) { }