/// <summary> /// Determines whether the specified expressions are equal. /// </summary> /// <param name="x">The first expression to compare.</param> /// <param name="y">The second expression to compare.</param> /// <returns><see langword="true" /> if the specified expressions are equal; otherwise, <see langword="false" />.</returns> /// <exception cref="ArgumentException"><paramref name="x"/> or <paramref name="y"/> are expressions that could not be parsed as a SQL expression.</exception> public bool Equals(string x, string y) { if (ReferenceEquals(x, y)) { return(true); } if (x is null || y is null) { return(false); } var tokenizer = new SqlServerTokenizer(); var xParseResult = tokenizer.TryTokenize(x); if (!xParseResult.HasValue) { throw new ArgumentException($"Could not parse the '{ nameof(x) }' string as a SQL expression. Given: { x }", nameof(x)); } var yParseResult = tokenizer.TryTokenize(y); if (!yParseResult.HasValue) { throw new ArgumentException($"Could not parse the '{ nameof(y) }' string as a SQL expression. Given: { y }", nameof(y)); } var xTokens = xParseResult.Value.ToList(); var yTokens = yParseResult.Value.ToList(); var xCleanedTokens = StripWrappingParens(xTokens); var yCleanedTokens = StripWrappingParens(yTokens); if (xCleanedTokens.Count != yCleanedTokens.Count) { return(false); } for (var i = 0; i < xCleanedTokens.Count; i++) { var xToken = xCleanedTokens[i]; var yToken = yCleanedTokens[i]; if (!TokensEqual(xToken, yToken)) { return(false); } } return(true); }
/// <summary> /// Retrieves all dependencies for an expression. /// </summary> /// <param name="objectName">The name of an object defined by an expression (e.g. a computed column definition).</param> /// <param name="expression">A SQL expression that may contain dependent object names.</param> /// <returns>A collection of identifiers found in the expression.</returns> /// <exception cref="ArgumentNullException"><paramref name="objectName"/> is <c>null</c>. Alternatively, if <paramref name="expression"/> is <c>null</c>, empty or whitespace.</exception> /// <exception cref="ArgumentException">Thrown when <paramref name="expression"/> could not be parsed as a valid SQL expression.</exception> /// <remarks>This will also return unqualified identifiers, which may cause ambiguity between object names and column names. Additionally it may return other identifiers, such as aliases or type names.</remarks> public IReadOnlyCollection <Identifier> GetDependencies(Identifier objectName, string expression) { if (objectName == null) { throw new ArgumentNullException(nameof(objectName)); } if (expression.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(expression)); } var tokenizer = new SqlServerTokenizer(); var tokenizeResult = tokenizer.TryTokenize(expression); if (!tokenizeResult.HasValue) { throw new ArgumentException($"Could not parse the given expression as a SQL expression. Given: { expression }", nameof(expression)); } var result = new HashSet <Identifier>(Comparer); var tokens = tokenizeResult.Value; var next = tokens.ConsumeToken(); while (next.HasValue) { var sqlIdentifier = SqlServerTokenParsers.QualifiedName(next.Location); if (sqlIdentifier.HasValue) { var dependentIdentifier = sqlIdentifier.Value; if (!Comparer.Equals(dependentIdentifier.Value, objectName)) { result.Add(dependentIdentifier.Value); } next = sqlIdentifier.Remainder.ConsumeToken(); } else { next = next.Remainder.ConsumeToken(); } } return(result); }