public async Task TestResolvedAttributeLimit() { CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(testsSubpath, "TestResolvedAttributeLimit"); CdmEntityDefinition mainEntity = await corpus.FetchObjectAsync <CdmEntityDefinition>("local:/mainEntity.cdm.json/mainEntity"); ResolveOptions resOpt = new ResolveOptions { WrtDoc = mainEntity.InDocument, Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "normalized", "referenceOnly" }) }; // if attribute limit is reached, entity should be null resOpt.ResolvedAttributeLimit = 4; var resEnt = await mainEntity.CreateResolvedEntityAsync($"{mainEntity.EntityName}_zeroAtts", resOpt); Assert.IsNull(resEnt); // when the attribute limit is set to null, there should not be a limit on the possible number of attributes resOpt.ResolvedAttributeLimit = null; resOpt.Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "normalized", "referenceOnly" }); var ras = mainEntity.FetchResolvedAttributes(resOpt); resEnt = await mainEntity.CreateResolvedEntityAsync($"{mainEntity.EntityName}_normalized_referenceOnly", resOpt); // there are 5 total attributes Assert.AreEqual(ras.ResolvedAttributeCount, 5); Assert.AreEqual(ras.Set.Count, 5); Assert.AreEqual(mainEntity.Attributes.Count, 3); // there are 2 attributes grouped in an entity attribute // and 2 attributes grouped in an attribute group Assert.AreEqual(((mainEntity.Attributes[2] as CdmAttributeGroupReference).ExplicitReference as CdmAttributeGroupDefinition).Members.Count, 2); // using the default limit number resOpt = new ResolveOptions { WrtDoc = mainEntity.InDocument, Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "normalized", "referenceOnly" }) }; ras = mainEntity.FetchResolvedAttributes(resOpt); resEnt = await mainEntity.CreateResolvedEntityAsync($"{mainEntity.EntityName}_normalized_referenceOnly", resOpt); // there are 5 total attributes Assert.AreEqual(ras.ResolvedAttributeCount, 5); Assert.AreEqual(ras.Set.Count, 5); Assert.AreEqual(mainEntity.Attributes.Count, 3); // there are 2 attributes grouped in an entity attribute // and 2 attributes grouped in an attribute group Assert.AreEqual(((mainEntity.Attributes[2] as CdmAttributeGroupReference).ExplicitReference as CdmAttributeGroupDefinition).Members.Count, 2); resOpt.Directives = new AttributeResolutionDirectiveSet(new HashSet <string> { "normalized", "structured" }); ras = mainEntity.FetchResolvedAttributes(resOpt); resEnt = await mainEntity.CreateResolvedEntityAsync($"{mainEntity.EntityName}_normalized_structured", resOpt); // there are 5 total attributes Assert.AreEqual(ras.ResolvedAttributeCount, 5); // the attribute count is different because one attribute is a group that contains two different attributes Assert.AreEqual(ras.Set.Count, 4); Assert.AreEqual(mainEntity.Attributes.Count, 3); // again there are 2 attributes grouped in an entity attribute // and 2 attributes grouped in an attribute group Assert.AreEqual(((mainEntity.Attributes[2] as CdmAttributeGroupReference).ExplicitReference as CdmAttributeGroupDefinition).Members.Count, 2); }
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); }