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());
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        /// <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);
        }