/// <summary> /// Create a constant entity that contains the source mapping to a foreign key. /// e.g. /// an fk created to entity "Customer" based on the "customerName", would add a parameter to the "is.linkedEntity.identifier" trait as follows: /// [ /// "/Customer.cdm.json/Customer", /// "customerName" /// ] /// In the case of polymorphic source, there will be a collection of such entries. /// </summary> /// <param name="corpus"></param> /// <param name="foundResAttrList"></param> /// <returns></returns> internal static CdmEntityReference CreateForeignKeyLinkedEntityIdentifierTraitParameter(ProjectionDirective projDir, CdmCorpusDefinition corpus, List <ProjectionAttributeState> refFoundList) { CdmEntityReference traitParamEntRef = null; List <Tuple <string, string> > entRefAndAttrNameList = new List <Tuple <string, string> >(); foreach (ProjectionAttributeState refFound in refFoundList) { ResolvedAttribute resAttr = refFound.CurrentResolvedAttribute; if (resAttr?.Target?.Owner != null && (resAttr.Target.ObjectType == CdmObjectType.TypeAttributeDef || resAttr.Target.ObjectType == CdmObjectType.EntityAttributeDef)) { // find the linked entity var owner = resAttr.Target.Owner; while (owner != null && owner.ObjectType != CdmObjectType.EntityDef) { owner = owner.Owner; } // find where the projection is defined var projectionDoc = projDir.Owner?.InDocument; if (owner?.ObjectType == CdmObjectType.EntityDef && projectionDoc != null) { CdmEntityDefinition entDef = owner.FetchObjectDefinition <CdmEntityDefinition>(projDir.ResOpt); if (entDef != null) { // should contain relative path without the namespace string relativeEntPath = entDef.Ctx.Corpus.Storage.CreateRelativeCorpusPath(entDef.AtCorpusPath, projectionDoc); entRefAndAttrNameList.Add(new Tuple <string, string>(relativeEntPath, resAttr.ResolvedName)); } } } } if (entRefAndAttrNameList.Count > 0) { CdmConstantEntityDefinition constantEntity = corpus.MakeObject <CdmConstantEntityDefinition>(CdmObjectType.ConstantEntityDef); constantEntity.EntityShape = corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, "entityGroupSet", true); string originalSourceEntityAttributeName = projDir.OriginalSourceEntityAttributeName; if (originalSourceEntityAttributeName == null) { originalSourceEntityAttributeName = ""; } constantEntity.ConstantValues = entRefAndAttrNameList.Select((entAndAttrName) => new List <string> { entAndAttrName.Item1, entAndAttrName.Item2, $"{originalSourceEntityAttributeName}_{entAndAttrName.Item1.Substring(entAndAttrName.Item1.LastIndexOf("/") + 1)}" }).ToList(); traitParamEntRef = corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, constantEntity, false); } return(traitParamEntRef); }
public static ConstantEntity ToData(CdmConstantEntityDefinition instance, ResolveOptions resOpt, CopyOptions options) { return(new ConstantEntity { Explanation = instance.Explanation, ConstantEntityName = instance.ConstantEntityName, EntityShape = Utils.JsonForm(instance.EntityShape, resOpt, options), ConstantValues = instance.ConstantValues }); }
internal void UpdateDefaultValue(dynamic newDefault) { if (newDefault is JArray) { JArray array = (JArray)newDefault; int l = array.Count; if (l > 0 && array[0]["languageTag"] != null && array[0]["displayText"] != null) { // looks like something we understand List <List <string> > tab = new List <List <string> >(); var corr = (array[0]["correlatedValue"] != null); for (var i = 0; i < l; i++) { var row = new List <string> { (string)array[i]["languageTag"], (string)array[i]["displayText"], (string)array[i]["attributeValue"], (string)array[i]["displayOrder"] }; if (corr) { row.Add((string)array[i]["correlatedValue"]); } tab.Add(row); } CdmConstantEntityDefinition cEnt = this.Ctx.Corpus.MakeObject <CdmConstantEntityDefinition>(CdmObjectType.ConstantEntityDef, null, false); cEnt.EntityShape = this.Ctx.Corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, corr ? "listLookupCorrelatedValues" : "listLookupValues", true); cEnt.ConstantValues = tab; newDefault = this.Ctx.Corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, cEnt, false); this.UpdateTraitArgument("does.haveDefault", "default", newDefault); } else { Logger.Error(nameof(TraitToPropertyMap), this.Host.Ctx, "Default value missing languageTag or displayText."); } } else { Logger.Error(nameof(TraitToPropertyMap), this.Host.Ctx, "Default value type not supported. Please use JArray."); } }
public static dynamic FetchReplacementValue(ResolveOptions resOpt, dynamic oldValue, dynamic newValue, bool wasSet) { if (oldValue == null) { return(newValue); } if (!wasSet) { // must explicitly set a value to override // if a new value is not set, then newValue holds nothing or the default. // in this case, if there was already a value in this argument then just keep using it. return(oldValue); } if (oldValue is string) { return(newValue); } CdmObject ov = oldValue as CdmObject; CdmObject nv = newValue as CdmObject; // replace an old table with a new table? actually just mash them together if (ov != null && ov.ObjectType == CdmObjectType.EntityRef && nv != null && nv.GetType() != typeof(string) && nv.ObjectType == CdmObjectType.EntityRef) { var oldEnt = ov.FetchObjectDefinition <CdmConstantEntityDefinition>(resOpt); var newEnt = nv.FetchObjectDefinition <CdmConstantEntityDefinition>(resOpt); // check that the entities are the same shape if (newEnt == null) { return(ov); } // BUG CdmEntityDefinition entDefShape = null; if (oldEnt == null || ((entDefShape = oldEnt.EntityShape.FetchObjectDefinition <CdmEntityDefinition>(resOpt)) != newEnt.EntityShape.FetchObjectDefinition <CdmEntityDefinition>(resOpt))) { return(nv); } var oldCv = oldEnt.ConstantValues; var newCv = newEnt.ConstantValues; // rows in old? if (oldCv == null || oldCv.Count == 0) { return(nv); } // rows in new? if (newCv == null || newCv.Count == 0) { return(ov); } // make a set of rows in the old one and add the new ones. this will union the two // find rows in the new one that are not in the old one. slow, but these are small usually IDictionary <string, List <string> > unionedRows = new Dictionary <string, List <string> >(); // see if any of the entity atts are the primary key, meaning, the only thing that causes us to merge dups unique. // i know this makes you think about a snake eating its own tail, but fetch the resolved attributes of the constant shape int pkAtt = -1; if (entDefShape != null) { var resOptShape = new ResolveOptions(entDefShape.InDocument); var resAttsShape = entDefShape.FetchResolvedAttributes(resOptShape); if (resAttsShape != null) { pkAtt = resAttsShape.Set.FindIndex((ra) => ra.ResolvedTraits.Find(resOptShape, "is.identifiedBy") != null); } } for (int i = 0; i < oldCv.Count; i++) { List <string> row = oldCv[i]; string key; // the entity might have a PK, if so, only look at that values as the key if (pkAtt != -1) { key = row[pkAtt]; } else { key = row.Aggregate((prev, curr) => { return($"{(!string.IsNullOrEmpty(prev) ? prev : "")}::{curr}"); }); } unionedRows[key] = row; } for (int i = 0; i < newCv.Count; i++) { List <string> row = newCv[i]; string key; // the entity might have a PK, if so, only look at that values as the key if (pkAtt != -1) { key = row[pkAtt]; } else { key = row.Aggregate((prev, curr) => { return($"{(!string.IsNullOrEmpty(prev) ? prev : "")}::{curr}"); }); } unionedRows[key] = row; } if (unionedRows.Count == oldCv.Count) { return(ov); } List <List <string> > allRows = unionedRows.Values.ToList(); CdmConstantEntityDefinition replacementEnt = (CdmConstantEntityDefinition)oldEnt.Copy(resOpt); replacementEnt.ConstantValues = allRows; return(resOpt.WrtDoc.Ctx.Corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, replacementEnt, false)); } return(newValue); }
public static dynamic FetchReplacementValue(ResolveOptions resOpt, dynamic oldValue, dynamic newValue, bool wasSet) { if (oldValue == null) { return(newValue); } if (!wasSet) { // must explicitly set a value to override // if a new value is not set, then newValue holds nothing or the default. // in this case, if there was already a value in this argument then just keep using it. return(oldValue); } if (oldValue is string) { return(newValue); } CdmObject ov = oldValue as CdmObject; CdmObject nv = newValue as CdmObject; // replace an old table with a new table? actually just mash them together if (ov != null && ov.ObjectType == CdmObjectType.EntityRef && nv != null && nv.GetType() != typeof(string) && nv.ObjectType == CdmObjectType.EntityRef) { var oldEnt = ov.FetchObjectDefinition <CdmConstantEntityDefinition>(resOpt); var newEnt = nv.FetchObjectDefinition <CdmConstantEntityDefinition>(resOpt); // check that the entities are the same shape if (newEnt == null) { return(ov); } // BUG if (oldEnt == null || (oldEnt.EntityShape.FetchObjectDefinition <CdmEntityDefinition>(resOpt) != newEnt.EntityShape.FetchObjectDefinition <CdmEntityDefinition>(resOpt))) { return(nv); } var oldCv = oldEnt.ConstantValues; var newCv = newEnt.ConstantValues; // rows in old? if (oldCv == null || oldCv.Count == 0) { return(nv); } // rows in new? if (newCv == null || newCv.Count == 0) { return(ov); } // make a set of rows in the old one and add the new ones. this will union the two // find rows in the new one that are not in the old one. slow, but these are small usually IDictionary <string, List <string> > unionedRows = new Dictionary <string, List <string> >(); for (int i = 0; i < oldCv.Count; i++) { List <string> row = oldCv[i]; string key = row.Aggregate((prev, curr) => { StringBuilder result = new StringBuilder(!string.IsNullOrEmpty(prev) ? prev : ""); result.Append("::"); result.Append(curr); return(result.ToString()); }); unionedRows[key] = row; } for (int i = 0; i < newCv.Count; i++) { List <string> row = newCv[i]; string key = row.Aggregate((prev, curr) => { StringBuilder result = new StringBuilder(!string.IsNullOrEmpty(prev) ? prev : ""); result.Append("::"); result.Append(curr); return(result.ToString()); }); unionedRows[key] = row; } if (unionedRows.Count == oldCv.Count) { return(ov); } List <List <string> > allRows = unionedRows.Values.ToList(); CdmConstantEntityDefinition replacementEnt = (CdmConstantEntityDefinition)oldEnt.Copy(resOpt); replacementEnt.ConstantValues = allRows; return(resOpt.WrtDoc.Ctx.Corpus.MakeRef <CdmEntityReference>(CdmObjectType.EntityRef, replacementEnt, false)); } return(newValue); }