public static void BuildDependencyTree(IDaxDependantObject expressionObj) { ClearDependsOn(expressionObj); foreach (var prop in expressionObj.GetDAXProperties()) { var dax = expressionObj.GetDAX(prop) ?? ""; ParseExpression(dax, expressionObj, prop); } }
public static IList <DaxToken> Tokenize(this IDaxDependantObject obj, DAXProperty property) { var result = new List <DaxToken>(); var dax = obj.GetDAX(property); if (string.IsNullOrEmpty(dax)) { return(result); } var lexer = new DAXLexer(new DAXCharStream(obj.GetDAX(property), false)); lexer.RemoveErrorListeners(); var lexerTokens = lexer.GetAllTokens(); for (int i = 0; i < lexerTokens.Count; i++) { result.Add(new DaxToken(lexerTokens[i], result, i)); } return(result); }
internal void UpdateRef(IDaxObject renamedObj) { // This method is called on a DependsOnList, which belongs to a IDaxDependantObject. The argument is the IDaxObject which was typically renamed. // For example: The DependsOnList could be attached to a Measure [MyMeasure] with an expression such as: "COUNTROWS('MyTable')". If the name of // 'MyTable' was changed, this method would be called with 'MyTable' as the renamedObj and [MyMeasure] as Parent. It is then up to this method // to loop through all object references to 'MyTable' (see #1). As an IDaxDependantObject can have more than one DAX expression property, and an // object reference to 'MyTable' could exist in any of them, we must make sure to loop all the properties (#2) List <ObjectReference> depList; if (TryGetValue(renamedObj, out depList)) // #1 Get a list of object references for renamedObj { var orgDax = new string[DaxPropertyCount]; var pos = new int[DaxPropertyCount]; var sbs = new StringBuilder[DaxPropertyCount]; foreach (var prop in Parent.GetDAXProperties()) // #2 Initialize a string buider and the original DAX for every DAX property on Parent { var dax = Parent.GetDAX(prop); if (dax != null) { sbs[(int)prop] = new StringBuilder(); orgDax[(int)prop] = dax.Replace("\r", ""); // Carriage Returns are excluded when the dependency tree is built } } // Loop through all dependencies: foreach (var dep in depList) { var propIx = (int)dep.property; var sb = sbs[propIx]; sb.Append(orgDax[propIx].Substring(pos[propIx], dep.from - pos[propIx])); sb.Append(dep.fullyQualified ? renamedObj.DaxObjectFullName : renamedObj.DaxObjectName); pos[propIx] = dep.to + 1; } // Finalize: foreach (var prop in Parent.GetDAXProperties()) { var propIx = (int)prop; if (pos[propIx] > 0) { sbs[propIx].Append(orgDax[propIx].Substring(pos[propIx])); Parent.SetDAX(prop, sbs[propIx].ToString()); } } } }
public static void BuildDependencyTree(IDaxDependantObject expressionObj) { foreach (var d in expressionObj.DependsOn.Keys) { d.ReferencedBy.Remove(expressionObj); } expressionObj.DependsOn.Clear(); foreach (var prop in expressionObj.GetDAXProperties()) { var dax = expressionObj.GetDAX(prop) ?? ""; ParseExpression(dax, expressionObj, prop); } }
internal void UpdateRef(IDaxObject renamedObj) { List <ObjectReference> depList; if (TryGetValue(renamedObj, out depList)) { var propertyCount = Enum.GetValues(typeof(DAXProperty)).Length; var pos = new int[propertyCount]; var sbs = new StringBuilder[propertyCount]; for (var i = 0; i < propertyCount; i++) { sbs[i] = new StringBuilder(); } // Loop through all dependencies: foreach (var dep in depList) { var propIx = (int)dep.property; var sb = sbs[propIx]; sb.Append(Parent.GetDAX(dep.property).Substring(pos[propIx], dep.from - pos[propIx])); sb.Append(dep.fullyQualified ? renamedObj.DaxObjectFullName : renamedObj.DaxObjectName); pos[propIx] = dep.to + 1; } // Finalize: for (var i = 0; i < propertyCount; i++) { if (pos[i] > 0) { sbs[i].Append(Parent.GetDAX((DAXProperty)i).Substring(pos[i])); Parent.SetDAX((DAXProperty)i, sbs[i].ToString()); } } } }
/// <summary> /// Rebuilds the dependency tree for the provided object. If within a BeginUpdate / EndUpdate batch, /// this operation is postponed until the batch ends unless force is set to true. /// </summary> /// <param name="expressionObj"></param> /// <param name="force"></param> public static void BuildDependencyTree(IDaxDependantObject expressionObj, bool force = false) { if (Handler.EoB_PostponeOperations && !force) { Handler.EoB_RequireRebuildDependencyTree = true; return; } ClearDependsOn(expressionObj); foreach (var prop in expressionObj.GetDAXProperties()) { var dax = expressionObj.GetDAX(prop) ?? ""; ParseExpression(dax, expressionObj, prop); } }
private void FixUpTest(TabularModelHandler tmh, IDaxDependantObject obj, Utils.DAXProperty property, bool isFullyQualified, Table tableRef, IDaxObject objRef) { var baseExpression = obj.GetDAX(property); if (isFullyQualified) { Assert.AreEqual(2, obj.DependsOn.Count); Assert.AreSame(tableRef, obj.DependsOn[0]); var references = obj.DependsOn[tableRef]; Assert.AreEqual(1, references.Count); Assert.AreEqual(property, references[0].property); Assert.IsTrue(references[0].fullyQualified); Assert.AreSame(objRef, obj.DependsOn[1]); references = obj.DependsOn[objRef]; Assert.AreEqual(1, references.Count); Assert.AreEqual(property, references[0].property); Assert.IsTrue(references[0].fullyQualified); } else { Assert.AreEqual(1, obj.DependsOn.Count); Assert.AreSame(objRef, obj.DependsOn[0]); var references = obj.DependsOn[objRef]; Assert.AreEqual(1, references.Count); Assert.AreEqual(property, references[0].property); Assert.IsFalse(references[0].fullyQualified); } var expression = baseExpression; var oldObjName = objRef.Name; objRef.Name = oldObjName + " Renamed"; var expr1 = expression = expression.Replace(oldObjName, objRef.Name); Assert.AreEqual(expression, obj.GetDAX(property)); var oldTableName = tableRef.Name; tableRef.Name = oldTableName + " Renamed"; var expr2 = expression = expression.Replace(oldTableName, tableRef.Name); Assert.AreEqual(expression, obj.GetDAX(property)); oldObjName = objRef.Name; objRef.Name = "b b"; var expr3 = expression = expression.Replace(oldObjName, objRef.Name); Assert.AreEqual(expression, obj.GetDAX(property)); oldTableName = tableRef.Name; tableRef.Name = "a a"; var expr4 = expression = expression.Replace(oldTableName, tableRef.Name); Assert.AreEqual(expression, obj.GetDAX(property)); tmh.UndoManager.Undo(); Assert.AreEqual(expr3, obj.GetDAX(property)); tmh.UndoManager.Undo(); Assert.AreEqual(expr2, obj.GetDAX(property)); tmh.UndoManager.Undo(); Assert.AreEqual(expr1, obj.GetDAX(property)); tmh.UndoManager.Undo(); Assert.AreEqual(baseExpression, obj.GetDAX(property)); }
public static void BuildDependencyTree(IDaxDependantObject expressionObj) { foreach (var d in expressionObj.DependsOn.Keys) { d.ReferencedBy.Remove(expressionObj); } expressionObj.DependsOn.Clear(); foreach (var prop in expressionObj.GetDAXProperties()) { var tokens = new DAXLexer(new AntlrInputStream(expressionObj.GetDAX(prop) ?? "")).GetAllTokens(); IToken lastTableRef = null; int startTableIndex = 0; for (var i = 0; i < tokens.Count; i++) { // TODO: This parsing could be used to check for invalid object references, for example to use in syntax highlighting or validation of expressions var tok = tokens[i]; switch (tok.Type) { case DAXLexer.TABLE: case DAXLexer.TABLE_OR_VARIABLE: if (i < tokens.Count - 1 && tokens[i + 1].Type == DAXLexer.COLUMN_OR_MEASURE) { // Keep the token reference, as the next token should be column (fully qualified). lastTableRef = tok; startTableIndex = tok.StartIndex; } else { // Table referenced directly, don't save the reference for the next token. lastTableRef = null; } if (Model.Tables.Contains(tok.Text.NoQ(true))) { expressionObj.AddDep(Model.Tables[tok.Text.NoQ(true)], prop, tok.StartIndex, tok.StopIndex, true); } else { // Invalid reference (no table with that name) or possibly a variable or function ref } break; case DAXLexer.COLUMN_OR_MEASURE: // Referencing a table just before the object reference if (lastTableRef != null) { var tableName = lastTableRef.Text.NoQ(true); lastTableRef = null; if (!Model.Tables.Contains(tableName)) { return; // Invalid reference (no table with that name) } var table = Model.Tables[tableName]; // Referencing a column on a specific table if (table.Columns.Contains(tok.Text.NoQ())) { expressionObj.AddDep(table.Columns[tok.Text.NoQ()], prop, startTableIndex, tok.StopIndex, true); } // Referencing a measure on a specific table else if (table.Measures.Contains(tok.Text.NoQ())) { expressionObj.AddDep(table.Measures[tok.Text.NoQ()], prop, startTableIndex, tok.StopIndex, true); } } // No table reference before the object reference else { var table = (expressionObj as ITabularTableObject)?.Table; // Referencing a column without specifying a table (assume column in same table): if (table != null && table.Columns.Contains(tok.Text.NoQ())) { expressionObj.AddDep(table.Columns[tok.Text.NoQ()], prop, tok.StartIndex, tok.StopIndex, false); } // Referencing a measure or column without specifying a table else { Measure m = null; if (table != null && table.Measures.Contains(tok.Text.NoQ())) { m = table.Measures[tok.Text.NoQ()]; } else { m = Model.Tables.FirstOrDefault(t => t.Measures.Contains(tok.Text.NoQ()))?.Measures[tok.Text.NoQ()]; } if (m != null) { expressionObj.AddDep(m, prop, tok.StartIndex, tok.StopIndex, false); } } } break; default: lastTableRef = null; break; } } } }