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

View file

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using MySql.Data.MySqlClient;
using TShockAPI.Extensions; using TShockAPI.Extensions;
namespace TShockAPI.DB namespace TShockAPI.DB
@ -10,19 +12,33 @@ namespace TShockAPI.DB
{ {
string CreateTable(SqlTable table); string CreateTable(SqlTable table);
string AlterTable(SqlTable from, SqlTable to); string AlterTable(SqlTable from, SqlTable to);
string DbTypeToString(MySqlDbType type, int? length);
} }
public class SqliteQueryCreator : IQueryBuilder public class SqliteQueryCreator : IQueryBuilder
{ {
public string CreateTable(SqlTable table) 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)); return "CREATE TABLE '{0}' ({1})".SFormat(table.Name, string.Join(", ", columns));
} }
static Random rand = new Random(); 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) 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" ALTER TABLE "main"."Bans" RENAME TO "oXHFcGcd04oXHFcGcd04_Bans"
CREATE TABLE "main"."Bans" ("IP" TEXT PRIMARY KEY ,"Name" TEXT) CREATE TABLE "main"."Bans" ("IP" TEXT PRIMARY KEY ,"Name" TEXT)
@ -30,18 +46,68 @@ namespace TShockAPI.DB
DROP TABLE "main"."oXHFcGcd04oXHFcGcd04_Bans" 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 class MysqlQueryCreator : IQueryBuilder
{ {
public string CreateTable(SqlTable table) 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 MySql.Data.MySqlClient;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
@ -9,7 +6,8 @@ namespace TShockAPI.DB
{ {
//Required //Required
public string Name { get; set; } public string Name { get; set; }
public string Type { get; set; } public MySqlDbType Type { get; set; }
//Optional //Optional
public bool Unique { get; set; } public bool Unique { get; set; }
@ -18,10 +16,20 @@ namespace TShockAPI.DB
public bool NotNull { get; set; } public bool NotNull { get; set; }
public string DefaultValue { 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; Name = name;
Type = type; Type = type;
Length = length;
} }
} }
} }

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data; using System.Data;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using MySql.Data.MySqlClient;
namespace TShockAPI.DB namespace TShockAPI.DB
{ {
@ -36,9 +37,10 @@ namespace TShockAPI.DB
var columns = GetColumns(table); var columns = GetColumns(table);
if (columns.Count > 0) 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 else
@ -61,7 +63,11 @@ namespace TShockAPI.DB
} }
else if (name == SqlType.Mysql) 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 else
{ {

View file

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