miniSql

6136600 » zgc123@gmail.com
11/19/2023 创建
#region License

// Copyright 2005-2019 Paul Kohler (https://github.com/paulkohler/minisqlquery). All rights reserved.
// This source code is made available under the terms of the GNU Lesser General Public License v3.0
// https://github.com/paulkohler/minisqlquery/blob/master/LICENSE
#endregion

using System.Collections.Generic;
using System.IO;

namespace MiniSqlQuery.Core.DbModel
{
    /// <summary>The sql writer.</summary>
    public class SqlWriter : ISqlWriter
    {
        /// <summary>Initializes a new instance of the <see cref="SqlWriter"/> class.</summary>
        public SqlWriter()
        {
            // todo - format options?
            IncludeComments = true;
            InsertLineBreaksBetweenColumns = true;
        }

        /// <summary>Gets or sets a value indicating whether IncludeComments.</summary>
        /// <value>The include comments.</value>
        public bool IncludeComments { get; set; }

        /// <summary>Gets or sets a value indicating whether InsertLineBreaksBetweenColumns.</summary>
        /// <value>The insert line breaks between columns.</value>
        public bool InsertLineBreaksBetweenColumns { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether to include read-only columns in the export SQL.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if including read-only columns in the export; otherwise, <c>false</c>.
        /// </value>
		public bool IncludeReadOnlyColumnsInExport { get; set; }

        /// <summary>The write create.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="column">The column.</param>
        public virtual void WriteCreate(TextWriter writer, DbModelColumn column)
        {
            writer.Write("{0} {1} ", MakeSqlFriendly(column.Name), column.DbType.Summary);

            if (!column.Nullable)
            {
                writer.Write("not ");
            }

            writer.Write("null");
        }

        /// <summary>The write delete.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="tableOrView">The table or view.</param>
        public virtual void WriteDelete(TextWriter writer, DbModelTable tableOrView)
        {
            writer.WriteLine("DELETE FROM");
            writer.Write("\t");
            writer.WriteLine(MakeSqlFriendly(tableOrView.FullName));
            writer.WriteLine("WHERE");

            for (int i = 0; i < tableOrView.PrimaryKeyColumns.Count; i++)
            {
                var column = tableOrView.PrimaryKeyColumns[i];
                writer.Write("\t{0} = ", MakeSqlFriendly(column.Name));
                if (i < tableOrView.PrimaryKeyColumns.Count - 1)
                {
                    writer.Write(" /*value:{0}*/ AND", column.Name);
                    writer.WriteLine();
                }
                else
                {
                    writer.Write("/*value:{0}*/", column.Name);
                }
            }

            writer.WriteLine();
        }

        /// <summary>The write insert.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="tableOrView">The table or view.</param>
        public virtual void WriteInsert(TextWriter writer, DbModelTable tableOrView)
        {
            writer.Write("INSERT INTO ");
            writer.Write(MakeSqlFriendly(tableOrView.FullName));
            if (InsertLineBreaksBetweenColumns)
            {
                writer.WriteLine();
                writer.Write("\t");
            }

            writer.Write("(");

            // get all columns that are "writable" including PKs that are not auto generated (unless specified)
            List<DbModelColumn> writableColumns = null;
            if (IncludeReadOnlyColumnsInExport)
            {
                writableColumns = tableOrView.Columns;
            }
            else
            {
                writableColumns = tableOrView.Columns.FindAll(c => c.IsWritable);
            }

            for (int i = 0; i < writableColumns.Count; i++)
            {
                var column = writableColumns[i];
                writer.Write(MakeSqlFriendly(column.Name));
                if (i < writableColumns.Count - 1)
                {
                    if (InsertLineBreaksBetweenColumns)
                    {
                        writer.WriteLine(",");
                        writer.Write("\t");
                    }
                    else
                    {
                        writer.Write(", ");
                    }
                }
            }

            writer.WriteLine(")");
            writer.Write("VALUES");
            if (InsertLineBreaksBetweenColumns)
            {
                writer.WriteLine();
                writer.Write("\t");
            }

            writer.Write("(");

            for (int i = 0; i < writableColumns.Count; i++)
            {
                var column = writableColumns[i];
                writer.Write(column.DbType.ToDDLValue(column.Nullable));
                if (IncludeComments)
                {
                    writer.Write(" /*{0},{1}*/", column.Name, column.DbType.Summary);
                }

                if (i < writableColumns.Count - 1)
                {
                    if (InsertLineBreaksBetweenColumns)
                    {
                        writer.WriteLine(",");
                        writer.Write("\t");
                    }
                    else
                    {
                        writer.Write(", ");
                    }
                }
            }

            writer.WriteLine(")");
        }

        /// <summary>The write select.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="tableOrView">The table or view.</param>
        public virtual void WriteSelect(TextWriter writer, DbModelTable tableOrView)
        {
            writer.Write("SELECT");
            writer.WriteLine();
            for (int i = 0; i < tableOrView.Columns.Count; i++)
            {
                writer.Write("\t");
                writer.Write(MakeSqlFriendly(tableOrView.Columns[i].Name));
                if (i < tableOrView.Columns.Count - 1)
                {
                    writer.Write(",");
                    writer.WriteLine();
                }
            }

            writer.WriteLine();
            writer.Write("FROM {0}", MakeSqlFriendly(tableOrView.FullName));
            writer.WriteLine();
        }

        /// <summary>The write select count.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="tableOrView">The table or view.</param>
        public virtual void WriteSelectCount(TextWriter writer, DbModelTable tableOrView)
        {
            writer.Write("SELECT COUNT(*) FROM {0}", MakeSqlFriendly(tableOrView.FullName));
            writer.WriteLine();
        }

        /// <summary>The write summary.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="column">The column.</param>
        public void WriteSummary(TextWriter writer, DbModelColumn column)
        {
            writer.Write("{0} ({1} ", MakeSqlFriendly(column.Name), column.DbType.Summary);

            if (!column.Nullable)
            {
                writer.Write("not ");
            }

            writer.Write("null)");
        }

        /// <summary>The write update.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="tableOrView">The table or view.</param>
        public virtual void WriteUpdate(TextWriter writer, DbModelTable tableOrView)
        {
            writer.Write("UPDATE ");
            writer.WriteLine(MakeSqlFriendly(tableOrView.FullName));
            writer.WriteLine("SET");

            // get all columns that are "writable" excluding keys that are not auto generated
            var writableColumns = tableOrView.Columns.FindAll(c => c.IsWritable && !c.IsKey);
            for (int i = 0; i < writableColumns.Count; i++)
            {
                var column = writableColumns[i];
                writer.Write("\t{0} = {1}", MakeSqlFriendly(column.Name), column.DbType.ToDDLValue(column.Nullable));
                if (i < writableColumns.Count - 1)
                {
                    writer.Write(",");
                    writer.WriteLine();
                }
            }

            writer.WriteLine();
            writer.WriteLine("WHERE");

            for (int i = 0; i < tableOrView.PrimaryKeyColumns.Count; i++)
            {
                var column = tableOrView.PrimaryKeyColumns[i];
                writer.Write("\t{0} = ", MakeSqlFriendly(column.Name));
                if (i < tableOrView.PrimaryKeyColumns.Count - 1)
                {
                    writer.Write(" /*value:{0},{1}*/ AND", column.Name, column.DbType.Summary);
                    writer.WriteLine();
                }
                else
                {
                    writer.Write("/*value:{0},{1}*/", column.Name, column.DbType.Summary);
                }
            }

            writer.WriteLine();
        }

        /// <summary>The make the sql friendly, e.g. "[TableName]".</summary>
        /// <param name="name">The name of the object.</param>
        /// <returns>The make sql friendly name.</returns>
        protected string MakeSqlFriendly(string name)
        {
            return Utility.MakeSqlFriendly(name);
        }
    }
}