Esempio n. 1
0
 /// <summary>
 /// Realiza a aplicação do template.
 ///
 /// Por padrão, todos os parâmetros atribuídos são estocados na instância
 /// de Sql e aplicados à string SQL apenas no ato da execução da SQL.
 ///
 /// Este método aplica o template imediatamente, modificando a SQL original,
 /// a menos que desativado pela configuração SequelSettings.QueryTemplateEnabled.
 ///
 /// Os parâmetros são aplicados ao template de duas formas:
 ///
 /// 1.  Posicional
 ///     Com ouso de String.Format parâmetros podem ser adicionados à string
 ///     na forma {0}, {1}, etc.
 ///
 /// 2.  Nomeado
 ///     Parâmetros nomeados podem aparecer na string na forma @{nome}.
 ///
 /// Exemplo:
 ///     var texto = "select * from {0} where @{campo} = @valor";
 ///     var sql = texto.AsSql();
 ///     sql.Format("usuario");
 ///     sql.Set("campo", "login");
 ///     sql.Set("valor", "Fulano");
 ///     sql.ApplyTemplate();
 ///
 ///     Resultado:
 ///       select * from usuario where login = @valor
 ///
 /// </summary>
 /// <param name="sql">A SQL a ser processada.</param>
 /// <returns>
 /// A mesma instância da SQL obtida como parâmetro para encadeamento
 /// de operações.
 /// </returns>
 public static Sql ApplyTemplate(this Sql sql)
 {
     return(ApplyTemplate(sql, false));
 }
Esempio n. 2
0
        /// <summary>
        /// Aplica uma substituição de parâmetro estendido no texto indicado.
        ///
        /// A função é complemento da função ApplyExtendedTemplate com a responsabilidade
        /// de localizar no texto as ocorrências do padrão "campo = {parametro}" realizando
        /// a substituição pela instrução comparadora definitiva.
        ///
        /// A porção "{parametro}" pode conter um valor booliano na forma: {parametro|valor}.
        /// Por padrão, quando o valor de um parâmetro não é definido o parâmetro é considerado
        /// bem sucedido pra qualquer registro, tornando nulo o parâmetro para fins de filtro.
        /// Este comportamento pode ser invertido pelo uso de "{parametro|0}" ou "{parametro|false}".
        /// Neste caso, o parâmetro é considerado mal sucedido e todos os registros passam a
        /// ser rejeitados nesta condição.
        /// </summary>
        /// <param name="text">O texto que sofrerá a substituição.</param>
        /// <param name="parameter">Nome do parametro procurado.</param>
        /// <param name="replacement">Texto que substituirá o padrão "campo = {parametro}"</param>
        /// <returns>O texto com a substituição efetuada.</returns>
        private static string ReplaceTemplate(Sql sql, string parameter, string replacement)
        {
            Regex           regex;
            MatchCollection matches;

            var text = sql.ToString();

            // Aplicando a substituição da instrução:
            //   @param is [not] set
            // Que deve ser tornar:
            //   1=1 quando verdadeiro
            //   1=0 quando falso
            regex   = new Regex("(@" + parameter + @"\s+is(\s+not)?\s+set)");
            matches = regex.Matches(text);
            foreach (var match in matches.Cast <Match>())
            {
                var isSet  = replacement != null;
                var negate = match.Groups[2].Value.Contains("not");
                if (negate)
                {
                    isSet = !isSet;
                }
                var criteria = isSet ? "1=1" : "1=0";
                text = text.Replace(match.Value, criteria);
            }

            // Aplicando a substituição da instrução:
            //   target [not] matches [if set] @param
            // Que deve ser substituído por "replacement", produzindo por exemplo:
            //   target = valor
            //   target >= valor
            //   target <= valor
            //   target in (valor, ...)
            //   target like valor
            //   target between valor and valor
            // Sendo que:
            //   quando "not" está presente a condição é invertida.
            //   quando "if set" está presente, se a condicao for nula, o resultado é verdadeiro:
            //     1=1
            //   quando "if set" não está presente, se a condicao for nula, o resultado é falso:
            //     1=0
            regex   = new Regex(@"(?:([a-zA-Z_.]+)|([a-zA-Z0-9_]*[(](?>[(](?<c>)|[^()]+|[)](?<-c>))*(?(c)(?!))[)]))\s+(not\s+)?matches\s+(if\s+set\s+)?@" + parameter);
            matches = regex.Matches(text);
            foreach (var match in matches.Cast <Match>())
            {
                string newSentence = null;

                if (replacement == null)
                {
                    // quando "if set" está presente, se a condicao for nula, o resultado é verdadeiro:
                    //   1=1
                    // quando "if set" não está presente, se a condicao for nula, o resultado é falso:
                    //   1=0
                    var ifSet = match.Groups[4].Value.Contains("set");
                    newSentence = ifSet ? "1=1" : "1=0";
                }
                else
                {
                    var leftSide = match.Groups[1].Value + match.Groups[2].Value;
                    newSentence = string.Format(replacement, leftSide);

                    var negate = match.Groups[3].Value.Contains("not");
                    if (negate)
                    {
                        newSentence = "not " + newSentence;
                    }
                }

                text = text.Replace(match.Value, newSentence);
            }

            return(text);
        }
Esempio n. 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);
        }