private static string Dump(Sql defaultSql) { var sql = defaultSql.Clone(); if (SequelSettings.QueryTemplateEnabled) { sql.ApplyTemplate(); } var text = sql.ToString().Beautify(); var lines = text.Split('\n', '\r').Where(x => !string.IsNullOrWhiteSpace(x)); var builder = new StringBuilder(); builder.AppendLine("Sql {"); builder.AppendLine(" Text {"); foreach (var line in lines) { builder.Append(" "); builder.AppendLine(line); } builder.AppendLine(" }"); builder.AppendLine(" Args {"); foreach (var parameter in sql.ParameterNames) { var value = Commander.CreateSqlCompatibleValue(sql[parameter]); builder.Append(" "); builder.Append(parameter); builder.Append(" := "); builder.AppendLine(value is DBNull ? "(null)" : $"\"{value}\""); } builder.AppendLine(" }"); builder.AppendLine("}"); return(builder.ToString()); }
/// <summary> /// Aplica o template simplificado de SQL. /// O template suporta a sintaxe: /// /// - @{parametro} /// /// Para realizar substituição no texto. /// /// Por exemplo, um nome de tabela pode ser definido dinamicamente e declarado /// no template como: /// /// SELECT * FROM @{nome_tabela} WHERE id = @id_tabela /// /// </summary> /// <param name="sql">The SQL.</param> public static void ApplyStandardTemplate(Sql sql) { var text = sql.ToString(); var names = from name in sql.ParameterNames orderby name.Length descending, name select name; foreach (var name in names) { var value = Commander.CreateSqlCompatibleValue(sql[name]); var key = "@{" + name + "}"; var keyValue = value.ToString(); text = text.Replace(key, keyValue); } sql.Text = text; }
/// <summary> /// Constrói a condição que substituirá o template baseado na instrução: /// - target [always] matches @parametro /// /// Se o valor do parâmetro não tiver sido definido o critério retornado será nulo. /// /// O critério criado contém o termo "{0}" que deve ser substituído pela /// parte "target" à direta da instrução matches. /// /// Por exemplo, em: /// Campo matches @nome /// /// O critério produzir pode ser algo como: /// {0} like @nome /// /// Que deve então ser substituído com String.Format() pela parte à direta /// da instrução, neste caso "Campo": /// String.Format("{0} like @nome", "Campo"); /// /// Produzindo como resultado: /// Campo like @nome /// </summary> /// <param name="parameter">Nome do parâmetro que será substituído.</param> /// <param name="value">Valor atribuído ao parâmetro.</param> /// <param name="args">Argumentos disponíveis.</param> /// <param name="keyGen">Algoritmo de geração de nomes de parâmetros.</param> /// <returns>A condição que substituirá o template.</returns> private static string CreateCriteria(string parameter, object value, IDictionary <string, object> args, KeyGen keyGen) { value = (value as Var)?.Value ?? value; if (value == null) { return(null); } if (value is string text) { if (text.HasWildcardPattern()) { args[parameter] = value; return("{0} like @" + parameter); } else { args[parameter] = value; return("{0} = @" + parameter); } } if (value.GetType().IsValueType) { args[parameter] = value; return("{0} = @" + parameter); } if (value is Sql nestSql) { var nestGen = keyGen.Derive(); var nestArgs = nestSql.Parameters; var nestText = nestSql.Text + "\n"; // cada parametro recebera um sufixo para diferenciacao de parametros // que já existem na instância de Sql. foreach (var key in nestArgs.Keys) { var matches = Regex.Matches(nestText, $@"@({key}\w?)"); foreach (Match match in matches.Cast <Match>().Reverse()) { var matchKey = match.Groups[1].Value; if (matchKey != key) { continue; } var index = match.Groups[1].Index; var count = match.Groups[1].Length; var keyName = nestGen.DeriveName(key); var keyValue = nestArgs[key]; args[keyName] = keyValue; nestText = nestText.Stuff(index, count, keyName); } } return("{0} in (" + nestText + ")"); } if (value is IEnumerable list) { var items = Commander.CreateSqlCompatibleValue(list); var values = string.Join(",", (IEnumerable)items); return("{0} in (" + values + ")"); } if (value is Range range) { if (range.Min != null && range.Max != null) { var minArg = keyGen.DeriveName(parameter); var maxArg = keyGen.DeriveName(parameter); args[minArg] = range.Min; args[maxArg] = range.Max; return("{0} between @" + minArg + " and @" + maxArg); } if (range.Min != null) { var minArg = keyGen.DeriveName(parameter); args[minArg] = range.Min; return("{0} >= @" + minArg); } if (range.Max != null) { var name = keyGen.DeriveName(parameter); args[name] = range.Max; return("{0} <= @" + name); } args[parameter] = value; return("{0} = @" + parameter); } args[parameter] = value; return("{0} = @" + parameter); }
private static string Dump(Sql defaultSql) { var sql = defaultSql.Clone(); if (SequelSettings.QueryTemplateEnabled) { sql.ApplyTemplate(); } var text = sql.Beautify().ToString(); var lines = text.Split('\n', '\r').Where(x => !string.IsNullOrWhiteSpace(x)); var builder = new StringBuilder(); builder.AppendLine("Sql {"); builder.AppendLine(" Text {"); foreach (var line in lines) { builder.Append(" "); builder.AppendLine(line); } builder.AppendLine(" }"); builder.AppendLine(" Args {"); foreach (var parameter in sql.ParameterNames) { builder.Append(" "); builder.Append(string.IsNullOrEmpty(parameter) ? "{many}" : parameter); builder.Append(" := "); var value = sql[parameter]; var var = value as Var; if (var?.IsRange == true) { builder.AppendLine($"{var.Range}"); } else if (var?.IsArray == true) { var items = var.Array.Cast <object>(); var item = items.FirstOrDefault(); var isMany = item.IsEnumerable(); var isBinary = item is byte; var isEmpty = !items.Any(); if (isEmpty) { builder.AppendLine("null"); } else if (isMany) { builder.AppendLine("{ ... }"); } else if (isBinary) { builder.AppendLine("binary"); } else { value = Commander.CreateSqlCompatibleValue(value); builder.AppendLine($"{{ {value} }}"); } } else { value = Commander.CreateSqlCompatibleValue(value); builder.AppendLine(value is DBNull ? "(null)" : $"\"{value}\""); } } builder.AppendLine(" }"); builder.AppendLine("}"); return(builder.ToString()); }
/// <summary> /// Constrói a condição que substituirá o template baseado na instrução: /// - target [always] matches @parametro /// /// Se o valor do parâmetro não tiver sido definido o critério retornado será nulo. /// /// O critério criado contém o termo "{0}" que deve ser substituído pela /// parte "target" à direta da instrução matches. /// /// Por exemplo, em: /// Campo matches @nome /// /// O critério produzir pode ser algo como: /// {0} like @nome /// /// Que deve então ser substituído com String.Format() pela parte à direta /// da instrução, neste caso "Campo": /// String.Format("{0} like @nome", "Campo"); /// /// Produzindo como resultado: /// Campo like @nome /// </summary> /// <param name="parameter">Nome do parâmetro que será substituído.</param> /// <param name="value">Valor atribuído ao parâmetro.</param> /// <param name="newParameters"> /// Coleção dos parâmetros conhecidos. /// Novos parâmetros podem ser criados nesta coleção para suporte ao critério criado. /// </param> /// <returns>A condição que substituirá o template.</returns> private static string CreateCriteria(Sql sql, string parameter, object value) { if (value == null || (value as Values)?.IsNull == true) { return(null); } if ((value as Values)?.IsValue == true) { value = ((Values)value).Value; } string criteria = null; if (value is Sql) { var innerSql = (Sql)value; innerSql.ApplyTemplate(false); var innerText = innerSql.Text + "\n"; // cada parametro recebera um sufixo para diferenciacao de parametros // que já existem na instância de Sql. foreach (var parameterName in innerSql.ParameterNames) { var localName = sql.KeyGen.Rename(parameterName); sql[localName] = innerSql[parameterName]; string pattern; string replacement; pattern = "@" + parameterName + "([^0-9A-Za-z_])"; replacement = "@" + localName + "$1"; innerText = Regex.Replace(innerText, pattern, replacement); pattern = "@{" + parameterName + "}"; replacement = "@{" + localName + "}"; innerText = innerText.Replace(pattern, replacement); } criteria = "{0} in (" + innerText + ")"; } else if ((value as Values)?.IsArray == true) { var items = Commander.CreateSqlCompatibleValue(value); var values = string.Join(",", items); criteria = "{0} in (" + values + ")"; } else if ((value as Values)?.IsRange == true) { var range = (Values)value; if (range.Min != null && range.Max != null) { var min = sql.KeyGen.Rename(parameter); var max = sql.KeyGen.Rename(parameter); criteria = "{0} between @" + min + " and @" + max; sql[min] = range.Min; sql[max] = range.Max; } else if (range.Min != null) { var name = sql.KeyGen.Rename(parameter); criteria = "{0} >= @" + name; sql[name] = range.Min; } else if (range.Max != null) { var name = sql.KeyGen.Rename(parameter); criteria = "{0} <= @" + name; sql[name] = range.Max; } else { criteria = "{0} = @" + parameter; sql[parameter] = value; } } else if ((value as Values)?.IsText == true) { var text = (Values)value; if (text.HasWildcard) { criteria = "{0} like @" + parameter; sql[parameter] = text.Text; } else { criteria = "{0} = @" + parameter; sql[parameter] = text.Text; } } else { criteria = "{0} = @" + parameter; sql[parameter] = value; } return(criteria); }