示例#1
0
        public void QueryInsertTest()
        {
            var query = Sql.From <Cliente>().Select(x => new Cliente
            {
                Nombre   = "Hola",
                Apellido = x.Apellido,
                Dir      = new Direccion
                {
                    Calle = x.Dir.Calle
                }
            });


            var clause = new InsertClause(
                table: "Cliente",
                value: null,
                query: query.Clause,
                onConflict: null,
                returning: null
                );

            var ret      = SqlInsertConverter.InsertToString(clause, ParamMode.Substitute, new SqlParamDic()).Sql;
            var expected = @"
INSERT INTO ""Cliente"" (Nombre, Apellido, Dir_Calle)
SELECT 
    'Hola' AS ""Nombre"", 
    ""x"".""Apellido"" AS ""Apellido"", 
    ""x"".""Dir_Calle"" AS ""Dir_Calle""
FROM ""Cliente"" ""x""
";

            AssertSql.AreEqual(expected, ret);
        }
示例#2
0
        private SqlResult CompileUpdateQuery(Query query)
        {
            SqlResult context = IntializeSQL_Result(query, "update");

            string table = MakeTable(context);

            InsertClause toUpdate = context.Query.GetOneComponent <InsertClause>("update", EngineCode);

            List <string> parts = MakeUpdateParts(toUpdate);

            context.Bindings.AddRange(toUpdate.Values);

            string where = CompileWheres(context);

            if (!string.IsNullOrEmpty(where))
            {
                where = " " + where;
            }

            string sets = string.Join(", ", parts);

            context.RawSql = $"UPDATE {table} SET {sets}{where}";

            return(context);
        }
示例#3
0
        public void SimpleReturning()
        {
            Expression <Func <Cliente> > valueExpr = () => new Cliente
            {
                Nombre   = "Rafael",
                Apellido = "Salguero",
            };

            Expression <Func <Cliente, ReturningTestType> > returningExpr = x => new ReturningTestType
            {
                id = x.IdRegistro
            };

            var clause = new InsertClause(
                table: "Cliente",
                value: valueExpr.Body,
                query: null,
                onConflict: null,
                returning: returningExpr
                );

            var ret      = SqlInsertConverter.InsertToString(clause, ParamMode.Substitute, new SqlParamDic()).Sql;
            var expected = @"
INSERT INTO ""Cliente"" (""Nombre"", ""Apellido"")
VALUES ('Rafael', 'Salguero')
RETURNING 
    ""Cliente"".""IdRegistro"" AS ""id""
";

            AssertSql.AreEqual(expected, ret);
        }
示例#4
0
        public void ComplexTypeInsertTest()
        {
            Expression <Func <Cliente> > valueExpr = () => new Cliente
            {
                Nombre   = "Rafael",
                Apellido = "Salguero",
                Dir      = new Direccion
                {
                    Calle      = "E Baca Calderon",
                    Personales = new DatosPersonales
                    {
                        Telefono = "4123"
                    }
                }
            };

            var clause = new InsertClause(
                table: "Cliente",
                value: valueExpr.Body,
                query: null,
                onConflict: null,
                returning: null
                );

            var ret      = SqlInsertConverter.InsertToString(clause, ParamMode.Substitute, new SqlParamDic()).Sql;
            var expected = @"
INSERT INTO ""Cliente"" (""Nombre"", ""Apellido"", ""Dir_Calle"", ""Dir_Personales_Telefono"")
VALUES ('Rafael', 'Salguero', 'E Baca Calderon', '4123')
";

            AssertSql.AreEqual(expected, ret);
        }
示例#5
0
        private List <string> MakeUpdateParts(InsertClause toUpdate)
        {
            List <string> parts = new List <string>();

            for (int column = 0; column < toUpdate.Columns.Count; column++)
            {
                parts.Add($"{wrapper.Wrap(toUpdate.Columns[column])} = ?");
            }
            return(parts);
        }
示例#6
0
        internal static Query RemoveColumn(this Query query, string column)
        {
            InsertClause clause  = (InsertClause)query.Clauses.FirstOrDefault(m => m is InsertClause);
            int          idIndex = clause.Columns.IndexOf(column);

            clause.Columns.RemoveAt(idIndex);
            clause.Values.RemoveAt(idIndex);

            return(query);
        }
示例#7
0
        private SqlResult InsertSqlClause(SqlResult context, string table, InsertClause insertClause)
        {
            string columns = string.Join(", ", WrapArray(insertClause.Columns));
            string values  = string.Join(", ", Parameterize(context, insertClause.Values));

            context.RawSql = $"INSERT INTO {table} ({columns}) VALUES ({values})";

            if (insertClause.ReturnId && !string.IsNullOrEmpty(wrapper.LastId))
            {
                context.RawSql += ";" + wrapper.LastId;
            }

            return(context);
        }
示例#8
0
        public void SimpleOnConflict()
        {
            Expression <Func <Cliente> > valueExpr = () => new Cliente
            {
                Nombre   = "Rafael",
                Apellido = "Salguero",
            };

            Expression <Func <Cliente, int> > indexExpr = x => x.IdRegistro;

            Expression <Func <Cliente, Cliente, Cliente> > updateExpr = (excluded, orig) => new Cliente
            {
                Nombre   = excluded.Nombre + orig.Nombre,
                Apellido = orig.Apellido,
                Tipo     = TipoPersona.Fisica
            };

            var doUpdate = new OnConflictDoUpdateClause(
                set: updateExpr,
                where : null
                );

            var onConf = new OnConflictClause(
                indexExpressions: new LambdaExpression[] { indexExpr },
                where : null,
                doUpdate: doUpdate
                );

            var clause = new InsertClause(
                table: "Cliente",
                value: valueExpr.Body,
                query: null,
                onConflict: onConf,
                returning: null
                );

            var ret      = SqlInsertConverter.InsertToString(clause, ParamMode.Substitute, new SqlParamDic()).Sql;
            var expected = @"
INSERT INTO ""Cliente"" (""Nombre"", ""Apellido"")
VALUES ('Rafael', 'Salguero')
ON CONFLICT (""IdRegistro"") DO UPDATE
SET
    ""Nombre"" = (EXCLUDED.""Nombre"" || ""Cliente"".""Nombre""), 
    ""Apellido"" = ""Cliente"".""Apellido"", 
    ""Tipo"" = 0
";

            AssertSql.AreEqual(expected, ret);
        }
示例#9
0
        public void VisitInsertClause(InsertClause insertClause, QueryModel queryModel)
        {
            if (insertClause.WithSelector != null)
            {
                QueryText.Append(" insert ");

                GetAqlExpression(insertClause.WithSelector, queryModel);
            }
            else
            {
                QueryText.AppendFormat(" insert {0} ", LinqUtility.ResolvePropertyName(insertClause.ItemName));
            }

            QueryText.AppendFormat(" in {0} ", LinqUtility.ResolveCollectionName(Db, insertClause.CollectionType));
        }
示例#10
0
        protected virtual string CompileInsertClause(SqlResult ctx, InsertClause insertClause)
        {
            var valueArray = new string[insertClause.Values.Count];

            for (var i = 0; i < insertClause.Values.Count; i++)
            {
                var value = insertClause.Values[i];
                if (value is Query valueQuery)
                {
                    var subCtx = CompileSelectQuery(valueQuery);

                    valueArray[i] = $"({subCtx.RawSql})";
                    ctx.Bindings.AddRange(subCtx.Bindings);
                }
                else
                {
                    valueArray[i] = Parameter(ctx, value);
                }
            }

            return(string.Join(", ", valueArray));
        }
示例#11
0
        public void SimpleInsertTest()
        {
            Expression <Func <Cliente> > valueExpr = () => new Cliente
            {
                Nombre   = "Rafael",
                Apellido = "Salguero",
            };

            var clause = new InsertClause(
                table: "Cliente",
                value: valueExpr.Body,
                query: null,
                onConflict: null,
                returning: null
                );

            var ret      = SqlInsertConverter.InsertToString(clause, ParamMode.Substitute, new SqlParamDic()).Sql;
            var expected = @"
INSERT INTO ""Cliente"" (""Nombre"", ""Apellido"")
VALUES ('Rafael', 'Salguero')
";

            AssertSql.AreEqual(expected, ret);
        }
示例#12
0
 protected PostgresInsertBase(IServiceProvider serviceProvider, InsertClause <TColumns> insertClause, OnConflictClause onConflictClause)
     : base(serviceProvider)
 {
     InsertClause     = insertClause;
     OnConflictClause = onConflictClause;
 }
示例#13
0
        private IQueryElement ConvertInternal(IQueryElement element, Func <IQueryElement, IQueryElement> action)
        {
            if (element == null)
            {
                return(null);
            }

            IQueryElement newElement;

            if (_visitedElements.TryGetValue(element, out newElement))
            {
                return(newElement);
            }

            switch (element.ElementType)
            {
            case EQueryElementType.SqlFunction:
            {
                var func  = (ISqlFunction)element;
                var parms = Convert(func.Parameters, action);

                if (parms != null && !ReferenceEquals(parms, func.Parameters))
                {
                    newElement = new SqlFunction(func.SystemType, func.Name, func.Precedence, parms);
                }

                break;
            }

            case EQueryElementType.SqlExpression:
            {
                var expr      = (ISqlExpression)element;
                var parameter = Convert(expr.Parameters, action);

                if (parameter != null && !ReferenceEquals(parameter, expr.Parameters))
                {
                    newElement = new SqlExpression(expr.SystemType, expr.Expr, expr.Precedence, parameter);
                }

                break;
            }

            case EQueryElementType.SqlBinaryExpression:
            {
                var bexpr = (ISqlBinaryExpression)element;
                var expr1 = (IQueryExpression)ConvertInternal(bexpr.Expr1, action);
                var expr2 = (IQueryExpression)ConvertInternal(bexpr.Expr2, action);

                if (expr1 != null && !ReferenceEquals(expr1, bexpr.Expr1) ||
                    expr2 != null && !ReferenceEquals(expr2, bexpr.Expr2))
                {
                    newElement = new SqlBinaryExpression(bexpr.SystemType, expr1 ?? bexpr.Expr1, bexpr.Operation,
                                                         expr2 ?? bexpr.Expr2, bexpr.Precedence);
                }

                break;
            }

            case EQueryElementType.SqlTable:
            {
                var table   = (ISqlTable)element;
                var fields1 = ToArray(table.Fields);
                var fields2 = Convert(fields1, action, f => new SqlField(f));
                var targs   = table.TableArguments == null
                        ? null
                        : Convert(table.TableArguments, action);

                var fe = fields2 == null || ReferenceEquals(fields1, fields2);
                var ta = ReferenceEquals(table.TableArguments, targs);

                if (!fe || !ta)
                {
                    if (fe)
                    {
                        fields2 = fields1;

                        for (var i = 0; i < fields2.Length; i++)
                        {
                            var field = fields2[i];

                            fields2[i] = new SqlField(field);

                            _visitedElements[field] = fields2[i];
                        }
                    }

                    newElement = new SqlTable(table, fields2, targs ?? table.TableArguments);
                }

                break;
            }

            case EQueryElementType.Column:
            {
                var col  = (IColumn)element;
                var expr = (IQueryExpression)ConvertInternal(col.Expression, action);

                IQueryElement parent;
                _visitedElements.TryGetValue(col.Parent, out parent);

                if (parent != null || expr != null && !ReferenceEquals(expr, col.Expression))
                {
                    newElement = new Column(parent == null
                            ? col.Parent
                            : (ISelectQuery)parent, expr ?? col.Expression, col.Alias);
                }

                break;
            }

            case EQueryElementType.TableSource:
            {
                var table  = (ITableSource)element;
                var source = (ISqlTableSource)ConvertInternal(table.Source, action);
                var joins  = Convert(table.Joins, action);

                if (source != null && !ReferenceEquals(source, table.Source) ||
                    joins != null && !ReferenceEquals(table.Joins, joins))
                {
                    newElement = new TableSource(source ?? table.Source, table.Alias, joins ?? table.Joins);
                }

                break;
            }

            case EQueryElementType.JoinedTable:
            {
                var join  = (IJoinedTable)element;
                var table = (ITableSource)ConvertInternal(join.Table, action);
                var cond  = (ISearchCondition)ConvertInternal(join.Condition, action);

                if (table != null && !ReferenceEquals(table, join.Table) ||
                    cond != null && !ReferenceEquals(cond, join.Condition))
                {
                    newElement = new JoinedTable(join.JoinType, table ?? join.Table, join.IsWeak,
                                                 cond ?? join.Condition);
                }

                break;
            }

            case EQueryElementType.SearchCondition:
            {
                var sc    = (ISearchCondition)element;
                var conds = Convert(sc.Conditions, action);

                if (conds != null && !ReferenceEquals(sc.Conditions, conds))
                {
                    newElement = new SearchCondition(conds);
                }

                break;
            }

            case EQueryElementType.Condition:
            {
                var c = (Condition)element;
                var p = (ISqlPredicate)ConvertInternal(c.Predicate, action);

                if (p != null && !ReferenceEquals(c.Predicate, p))
                {
                    newElement = new Condition(c.IsNot, p, c.IsOr);
                }

                break;
            }

            case EQueryElementType.ExprPredicate:
            {
                var p = (IExpr)element;
                var e = (IQueryExpression)ConvertInternal(p.Expr1, action);

                if (e != null && !ReferenceEquals(p.Expr1, e))
                {
                    newElement = new Expr(e, p.Precedence);
                }

                break;
            }

            case EQueryElementType.NotExprPredicate:
            {
                var p = (INotExpr)element;
                var e = (IQueryExpression)ConvertInternal(p.Expr1, action);

                if (e != null && !ReferenceEquals(p.Expr1, e))
                {
                    newElement = new NotExpr(e, p.IsNot, p.Precedence);
                }

                break;
            }

            case EQueryElementType.ExprExprPredicate:
            {
                var p  = (IExprExpr)element;
                var e1 = (IQueryExpression)ConvertInternal(p.Expr1, action);
                var e2 = (IQueryExpression)ConvertInternal(p.Expr2, action);

                if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2))
                {
                    newElement = new ExprExpr(e1 ?? p.Expr1, p.EOperator, e2 ?? p.Expr2);
                }

                break;
            }

            case EQueryElementType.LikePredicate:
            {
                var p  = (ILike)element;
                var e1 = (IQueryExpression)ConvertInternal(p.Expr1, action);
                var e2 = (IQueryExpression)ConvertInternal(p.Expr2, action);
                var es = (IQueryExpression)ConvertInternal(p.Escape, action);

                if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2) ||
                    es != null && !ReferenceEquals(p.Escape, es))
                {
                    newElement = new Like(e1 ?? p.Expr1, p.IsNot, e2 ?? p.Expr2, es ?? p.Escape);
                }

                break;
            }

            case EQueryElementType.HierarhicalPredicate:
            {
                var p  = (IHierarhicalPredicate)element;
                var e1 = (IQueryExpression)ConvertInternal(p.Expr1, action);
                var e2 = (IQueryExpression)ConvertInternal(p.Expr2, action);

                if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2))
                {
                    newElement = new HierarhicalPredicate(e1 ?? p.Expr1, e2 ?? p.Expr2, p.Flow);
                }

                break;
            }

            case EQueryElementType.BetweenPredicate:
            {
                var p  = (IBetween)element;
                var e1 = (IQueryExpression)ConvertInternal(p.Expr1, action);
                var e2 = (IQueryExpression)ConvertInternal(p.Expr2, action);
                var e3 = (IQueryExpression)ConvertInternal(p.Expr3, action);

                if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2) ||
                    e3 != null && !ReferenceEquals(p.Expr3, e3))
                {
                    newElement = new Between(e1 ?? p.Expr1, p.IsNot, e2 ?? p.Expr2, e3 ?? p.Expr3);
                }

                break;
            }

            case EQueryElementType.IsNullPredicate:
            {
                var p = (IIsNull)element;
                var e = (IQueryExpression)ConvertInternal(p.Expr1, action);

                if (e != null && !ReferenceEquals(p.Expr1, e))
                {
                    newElement = new IsNull(e, p.IsNot);
                }

                break;
            }

            case EQueryElementType.InSubQueryPredicate:
            {
                var p = (IInSubQuery)element;
                var e = (IQueryExpression)ConvertInternal(p.Expr1, action);
                var q = (ISelectQuery)ConvertInternal(p.SubQuery, action);

                if (e != null && !ReferenceEquals(p.Expr1, e) || q != null && !ReferenceEquals(p.SubQuery, q))
                {
                    newElement = new InSubQuery(e ?? p.Expr1, p.IsNot, q ?? p.SubQuery);
                }

                break;
            }

            case EQueryElementType.InListPredicate:
            {
                var p = (IInList)element;
                var e = (IQueryExpression)ConvertInternal(p.Expr1, action);
                var v = Convert(p.Values, action);

                if (e != null && !ReferenceEquals(p.Expr1, e) || v != null && !ReferenceEquals(p.Values, v))
                {
                    newElement = new InList(e ?? p.Expr1, p.IsNot, v ?? p.Values);
                }

                break;
            }

            case EQueryElementType.FuncLikePredicate:
            {
                var p = (IFuncLike)element;
                var f = (ISqlFunction)ConvertInternal(p.Function, action);

                if (f != null && !ReferenceEquals(p.Function, f))
                {
                    newElement = new FuncLike(f);
                }

                break;
            }

            case EQueryElementType.SetExpression:
            {
                var s = (ISetExpression)element;
                var c = (IQueryExpression)ConvertInternal(s.Column, action);
                var e = (IQueryExpression)ConvertInternal(s.Expression, action);

                if (c != null && !ReferenceEquals(s.Column, c) || e != null && !ReferenceEquals(s.Expression, e))
                {
                    newElement = new SetExpression(c ?? s.Column, e ?? s.Expression);
                }

                break;
            }

            case EQueryElementType.InsertClause:
            {
                var s = (IInsertClause)element;
                var t = s.Into != null
                        ? (ISqlTable)ConvertInternal(s.Into, action)
                        : null;
                var i = Convert(s.Items, action);

                if (t != null && !ReferenceEquals(s.Into, t) || i != null && !ReferenceEquals(s.Items, i))
                {
                    var sc = new InsertClause
                    {
                        Into = t ?? s.Into
                    };

                    (i ?? s.Items).ForEach(node => sc.Items.AddLast(node.Value));

                    sc.WithIdentity = s.WithIdentity;

                    newElement = sc;
                }

                break;
            }

            case EQueryElementType.UpdateClause:
            {
                var s = (IUpdateClause)element;
                var t = s.Table != null
                        ? (ISqlTable)ConvertInternal(s.Table, action)
                        : null;
                var i = Convert(s.Items, action);
                var k = Convert(s.Keys, action);

                if (t != null && !ReferenceEquals(s.Table, t) || i != null && !ReferenceEquals(s.Items, i) ||
                    k != null && !ReferenceEquals(s.Keys, k))
                {
                    var sc = new UpdateClause
                    {
                        Table = t ?? s.Table
                    };

                    (i ?? s.Items).ForEach(node => sc.Items.AddLast(node.Value));
                    (k ?? s.Keys).ForEach(node => sc.Keys.AddLast(node.Value));

                    newElement = sc;
                }

                break;
            }

            case EQueryElementType.DeleteClause:
            {
                var s = (IDeleteClause)element;
                var t = s.Table != null
                        ? (ISqlTable)ConvertInternal(s.Table, action)
                        : null;

                if (t != null && !ReferenceEquals(s.Table, t))
                {
                    newElement = new DeleteClause
                    {
                        Table = t
                    };
                }

                break;
            }

            case EQueryElementType.CreateTableStatement:
            {
                var s = (ICreateTableStatement)element;
                var t = s.Table != null
                        ? (ISqlTable)ConvertInternal(s.Table, action)
                        : null;

                if (t != null && !ReferenceEquals(s.Table, t))
                {
                    newElement = new CreateTableStatement
                    {
                        Table  = t,
                        IsDrop = s.IsDrop
                    };
                }

                break;
            }

            case EQueryElementType.SelectClause:
            {
                var sc   = (ISelectClause)element;
                var cols = Convert(sc.Columns, action);
                var take = (IQueryExpression)ConvertInternal(sc.TakeValue, action);
                var skip = (IQueryExpression)ConvertInternal(sc.SkipValue, action);

                IQueryElement parent;
                _visitedElements.TryGetValue(sc.SelectQuery, out parent);

                if (parent != null || cols != null && !ReferenceEquals(sc.Columns, cols) ||
                    take != null && !ReferenceEquals(sc.TakeValue, take) ||
                    skip != null && !ReferenceEquals(sc.SkipValue, skip))
                {
                    newElement = new SelectClause(sc.IsDistinct, take ?? sc.TakeValue, skip ?? sc.SkipValue,
                                                  cols ?? sc.Columns);
                    ((ISelectClause)newElement).SetSqlQuery((ISelectQuery)parent);
                }

                break;
            }

            case EQueryElementType.FromClause:
            {
                var fc = (IFromClause)element;
                var ts = Convert(fc.Tables, action);

                IQueryElement parent;
                _visitedElements.TryGetValue(fc.SelectQuery, out parent);

                if (parent != null || ts != null && !ReferenceEquals(fc.Tables, ts))
                {
                    newElement = new FromClause(ts ?? fc.Tables);
                    ((IFromClause)newElement).SetSqlQuery((ISelectQuery)parent);
                }

                break;
            }

            case EQueryElementType.WhereClause:
            {
                var wc   = (IWhereClause)element;
                var cond = (ISearchCondition)ConvertInternal(wc.Search, action);

                IQueryElement parent;
                _visitedElements.TryGetValue(wc.SelectQuery, out parent);

                if (parent != null || cond != null && !ReferenceEquals(wc.Search, cond))
                {
                    newElement = new WhereClause(cond ?? wc.Search);
                    ((IWhereClause)newElement).SetSqlQuery((ISelectQuery)parent);
                }

                break;
            }

            case EQueryElementType.GroupByClause:
            {
                var gc = (IGroupByClause)element;
                var es = Convert(gc.Items, action);

                IQueryElement parent;
                _visitedElements.TryGetValue(gc.SelectQuery, out parent);

                if (parent != null || es != null && !ReferenceEquals(gc.Items, es))
                {
                    newElement = new GroupByClause(es ?? gc.Items);
                    ((IGroupByClause)newElement).SetSqlQuery((ISelectQuery)parent);
                }

                break;
            }

            case EQueryElementType.OrderByClause:
            {
                var oc = (IOrderByClause)element;
                var es = Convert(oc.Items, action);

                IQueryElement parent;
                _visitedElements.TryGetValue(oc.SelectQuery, out parent);

                if (parent != null || es != null && !ReferenceEquals(oc.Items, es))
                {
                    newElement = new OrderByClause(es ?? oc.Items);
                    ((IOrderByClause)newElement).SetSqlQuery((ISelectQuery)parent);
                }

                break;
            }

            case EQueryElementType.OrderByItem:
            {
                var i = (IOrderByItem)element;
                var e = (IQueryExpression)ConvertInternal(i.Expression, action);

                if (e != null && !ReferenceEquals(i.Expression, e))
                {
                    newElement = new OrderByItem(e, i.IsDescending);
                }

                break;
            }

            case EQueryElementType.Union:
            {
                var u = (IUnion)element;
                var q = (ISelectQuery)ConvertInternal(u.SelectQuery, action);

                if (q != null && !ReferenceEquals(u.SelectQuery, q))
                {
                    newElement = new Union(q, u.IsAll);
                }

                break;
            }

            case EQueryElementType.SqlQuery:
            {
                var           q      = (ISelectQuery)element;
                IQueryElement parent = null;

                var doConvert = false;

                if (q.ParentSelect != null)
                {
                    if (!_visitedElements.TryGetValue(q.ParentSelect, out parent))
                    {
                        doConvert = true;
                        parent    = q.ParentSelect;
                    }
                }

                if (!doConvert)
                {
                    doConvert = null != FindFirstOrDefault <IQueryElement>(q, e =>
                        {
                            if (_visitedElements.ContainsKey(e) && _visitedElements[e] != e)
                            {
                                return(true);
                            }

                            var ret = action(e);

                            if (ret != null && !ReferenceEquals(e, ret))
                            {
                                _visitedElements.Add(e, ret);
                                return(true);
                            }

                            return(false);
                        });
                }

                if (!doConvert)
                {
                    break;
                }

                var nq = new SelectQuery
                {
                    EQueryType = q.EQueryType
                };

                _visitedElements.Add(q, nq);

                var fc = (IFromClause)ConvertInternal(q.From, action) ?? q.From;
                var sc = (ISelectClause)ConvertInternal(q.Select, action) ?? q.Select;
                var ic = q.IsInsert
                        ? ((IInsertClause)ConvertInternal(q.Insert, action) ?? q.Insert)
                        : null;
                var uc = q.IsUpdate
                        ? ((IUpdateClause)ConvertInternal(q.Update, action) ?? q.Update)
                        : null;
                var dc = q.IsDelete
                        ? ((IDeleteClause)ConvertInternal(q.Delete, action) ?? q.Delete)
                        : null;
                var wc = (IWhereClause)ConvertInternal(q.Where, action) ?? q.Where;
                var gc = (IGroupByClause)ConvertInternal(q.GroupBy, action) ?? q.GroupBy;
                var hc = (IWhereClause)ConvertInternal(q.Having, action) ?? q.Having;
                var oc = (IOrderByClause)ConvertInternal(q.OrderBy, action) ?? q.OrderBy;
                var us = q.HasUnion
                        ? Convert(q.Unions, action)
                        : q.Unions;

                var ps = new List <ISqlParameter>(q.Parameters.Count);

                foreach (var p in q.Parameters)
                {
                    IQueryElement e;

                    if (_visitedElements.TryGetValue(p, out e))
                    {
                        if (e == null)
                        {
                            ps.Add(p);
                        }
                        else
                        {
                            var sqlParameter = e as ISqlParameter;
                            if (sqlParameter != null)
                            {
                                ps.Add(sqlParameter);
                            }
                        }
                    }
                }

                nq.Init(ic, uc, dc, sc, fc, wc, gc, hc, oc, us, (ISelectQuery)parent, q.CreateTable,
                        q.IsParameterDependent, ps);

                _visitedElements[q] = action(nq) ?? nq;

                return(nq);
            }
            }

            newElement = newElement == null
                ? action(element)
                : (action(newElement) ?? newElement);

            _visitedElements.Add(element, newElement);

            return(newElement);
        }