Finished:

-sqlite altering
-implemented mysql
Todo:
-Merge SqlTableCreator into the querybuilders or make it static
-Make all the managers use the querybuilder for making tables. (See GroupManager.cs for an example)
-Implement more datatypes (see TypesAsStrings in IQueryBuilder.cs)
This commit is contained in:
high 2011-08-03 18:37:42 -04:00
parent 3e045d51bf
commit 423a33325a
5 changed files with 101 additions and 20 deletions

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
@ -18,13 +19,13 @@ namespace TShockAPI.DB
string query = "";
var table = new SqlTable("GroupList",
new SqlColumn("GroupName", "TEXT") { Primary = true },
new SqlColumn("Commands", "TEXT"),
new SqlColumn("ChatColor", "TEXT")
/*var table = new SqlTable("GroupList",
new SqlColumn("GroupName", MySqlDbType.VarChar, 32) { Primary = true },
new SqlColumn("Commands", MySqlDbType.Text),
new SqlColumn("ChatColor", MySqlDbType.Text)
);
//new SqlTableCreator(db).EnsureExists(table);
new SqlTableCreator(db, new MysqlQueryCreator()).EnsureExists(table);*/
if (db.GetSqlType() == SqlType.Sqlite)

View file

@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using TShockAPI.Extensions;
namespace TShockAPI.DB
@ -10,19 +12,33 @@ namespace TShockAPI.DB
{
string CreateTable(SqlTable table);
string AlterTable(SqlTable from, SqlTable to);
string DbTypeToString(MySqlDbType type, int? length);
}
public class SqliteQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
var columns = table.Columns.Select(c => "'{0}' {1} {2} {3} {4}".SFormat(c.Name, c.Type, c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "", c.Unique ? "UNIQUE" : ""));
var columns = table.Columns.Select(c => "'{0}' {1} {2} {3} {4}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "", c.Unique ? "UNIQUE" : ""));
return "CREATE TABLE '{0}' ({1})".SFormat(table.Name, string.Join(", ", columns));
}
static Random rand = new Random();
/// <summary>
/// Alter a table from source to destination
/// </summary>
/// <param name="from">Must have name and column names. Column types are not required</param>
/// <param name="to">Must have column names and column types.</param>
/// <returns></returns>
public string AlterTable(SqlTable from, SqlTable to)
{
return "";
var rstr = rand.NextString(20);
var alter = "ALTER TABLE '{0}' RENAME TO '{1}_{0}'".SFormat(from.Name, rstr);
var create = CreateTable(to);
//combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable.
//exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data?
var insert = "INSERT INTO '{0}' ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name, string.Join(", ", from.Columns.Where(c => to.Columns.Any(c2 => c2.Name == c.Name)).Select(c => c.Name)), rstr);
var drop = "DROP TABLE '{0}_{1}'".SFormat(rstr, from.Name);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
/*
ALTER TABLE "main"."Bans" RENAME TO "oXHFcGcd04oXHFcGcd04_Bans"
CREATE TABLE "main"."Bans" ("IP" TEXT PRIMARY KEY ,"Name" TEXT)
@ -30,18 +46,68 @@ namespace TShockAPI.DB
DROP TABLE "main"."oXHFcGcd04oXHFcGcd04_Bans"
*/
}
static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{
{MySqlDbType.VarChar, "TEXT"},
{MySqlDbType.String, "TEXT"},
{MySqlDbType.Text, "TEXT"},
{MySqlDbType.TinyText, "TEXT"},
{MySqlDbType.MediumText, "TEXT"},
{MySqlDbType.LongText, "TEXT"},
};
public string DbTypeToString(MySqlDbType type, int? length)
{
string ret;
if (TypesAsStrings.TryGetValue(type, out ret))
return ret;
throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
}
}
public class MysqlQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
throw new NotImplementedException();
var columns = table.Columns.Select(c => "{0} {1} {2} {3}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : ""));
var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name);
return "CREATE TABLE {0} ({1}) {2}".SFormat(table.Name, string.Join(", ", columns), uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : "");
}
static Random rand = new Random();
/// <summary>
/// Alter a table from source to destination
/// </summary>
/// <param name="from">Must have name and column names. Column types are not required</param>
/// <param name="to">Must have column names and column types.</param>
/// <returns></returns>
public string AlterTable(SqlTable from, SqlTable to)
{
var rstr = rand.NextString(20);
var alter = "RENAME TABLE {0} TO {1}_{0}".SFormat(from.Name, rstr);
var create = CreateTable(to);
//combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable.
//exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data?
var insert = "INSERT INTO {0} ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name, string.Join(", ", from.Columns.Where(c => to.Columns.Any(c2 => c2.Name == c.Name)).Select(c => c.Name)), rstr);
var drop = "DROP TABLE {0}_{1}".SFormat(rstr, from.Name);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
}
public string AlterTable(SqlTable from, SqlTable to)
static readonly Dictionary<MySqlDbType, string> TypesAsStrings = new Dictionary<MySqlDbType, string>
{
throw new NotImplementedException();
{MySqlDbType.VarChar, "VARCHAR"},
{MySqlDbType.String, "CHAR"},
{MySqlDbType.Text, "TEXT"},
{MySqlDbType.TinyText, "TINYTEXT"},
{MySqlDbType.MediumText, "MEDIUMTEXT"},
{MySqlDbType.LongText, "LONGTEXT"},
};
public string DbTypeToString(MySqlDbType type, int? length)
{
string ret;
if (TypesAsStrings.TryGetValue(type, out ret))
return ret + (length != null ? "({0})".SFormat((int)length) : "");
throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
}
}
}

View file

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
@ -9,7 +6,8 @@ namespace TShockAPI.DB
{
//Required
public string Name { get; set; }
public string Type { get; set; }
public MySqlDbType Type { get; set; }
//Optional
public bool Unique { get; set; }
@ -18,10 +16,20 @@ namespace TShockAPI.DB
public bool NotNull { get; set; }
public string DefaultValue { get; set; }
public SqlColumn(string name, string type)
/// <summary>
/// Length of the data type, null = default
/// </summary>
public int? Length { get; set; }
public SqlColumn(string name, MySqlDbType type)
: this(name, type, null)
{
}
public SqlColumn(string name, MySqlDbType type, int? length)
{
Name = name;
Type = type;
Length = length;
}
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
@ -36,9 +37,10 @@ namespace TShockAPI.DB
var columns = GetColumns(table);
if (columns.Count > 0)
{
if (table.Columns.All(c => columns.Contains(c.Name)))
if (!table.Columns.All(c => columns.Contains(c.Name)) || !columns.All(c => table.Columns.Any(c2 => c2.Name == c)))
{
var from = new SqlTable(table.Name, columns.Select(s => new SqlColumn(s, MySqlDbType.String)).ToList());
database.Query(creator.AlterTable(from, table));
}
}
else
@ -61,7 +63,11 @@ namespace TShockAPI.DB
}
else if (name == SqlType.Mysql)
{
throw new NotImplementedException();
using (var reader = database.QueryReader("SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME=@0 AND TABLE_SCHEMA=@1", table.Name, database.Database))
{
while (reader.Read())
ret.Add(reader.Get<string>("COLUMN_NAME"));
}
}
else
{

View file

@ -71,7 +71,7 @@ namespace TShockAPI.DB
var name = conn.GetType().Name;
if (name == "SqliteConnection")
return SqlType.Sqlite;
if (name == "MysqlConnection")
if (name == "MySqlConnection")
return SqlType.Mysql;
return SqlType.Unknown;
}