/*
TShock, a server mod for Terraria
Copyright (C) 2011-2025 Pryaxis & TShock Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using TShockAPI.Extensions;
namespace TShockAPI.DB.Queries;
///
/// A Generic Query Creator (abstract)
///
public abstract class GenericQueryBuilder : IQueryBuilder
{
protected static Random rand = new Random();
///
/// Escapes the table name
///
/// The name of the table to be escaped
///
protected abstract string EscapeTableName(string table);
///
public abstract string CreateTable(SqlTable table);
///
public abstract string RenameTable(string from, string to);
///
public string AlterTable(SqlTable from, SqlTable to)
{
var rstr = rand.NextString(20);
var escapedTable = EscapeTableName(from.Name);
var tmpTable = EscapeTableName("{0}_{1}".SFormat(rstr, from.Name));
var alter = RenameTable(escapedTable, tmpTable);
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 columns = string.Join(", ", from.Columns.Where(c => to.Columns.Any(c2 => c2.Name == c.Name)).Select(c => $"`{c.Name}`"));
var insert = "INSERT INTO {0} ({1}) SELECT {1} FROM {2}".SFormat(escapedTable, columns, tmpTable);
var drop = "DROP TABLE {0}".SFormat(tmpTable);
return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop);
}
///
public abstract string DbTypeToString(MySqlDbType type, int? length);
///
/// Check for errors in the columns.
///
///
///
protected static void ValidateSqlColumnType(List columns)
{
columns.ForEach(x =>
{
if (x.DefaultCurrentTimestamp && x.Type != MySqlDbType.DateTime)
{
throw new SqlColumnException(GetString("Can't set to true SqlColumn.DefaultCurrentTimestamp when the MySqlDbType is not DateTime"));
}
});
}
///
public string DeleteRow(string table, List wheres)
{
return "DELETE FROM {0} {1}".SFormat(EscapeTableName(table), BuildWhere(wheres));
}
///
public string UpdateValue(string table, List values, List wheres)
{
if (0 == values.Count)
throw new ArgumentException(GetString("No values supplied"));
return "UPDATE {0} SET {1} {2}".SFormat(EscapeTableName(table), string.Join(", ", values.Select(v => v.Name + " = " + v.Value)), BuildWhere(wheres));
}
///
public string ReadColumn(string table, List wheres)
{
return "SELECT * FROM {0} {1}".SFormat(EscapeTableName(table), BuildWhere(wheres));
}
public string InsertValues(string table, List values)
{
var sbnames = new StringBuilder();
var sbvalues = new StringBuilder();
int count = 0;
foreach (SqlValue value in values)
{
sbnames.Append(value.Name);
sbvalues.Append(value.Value.ToString());
if (count != values.Count - 1)
{
sbnames.Append(", ");
sbvalues.Append(", ");
}
count++;
}
return "INSERT INTO {0} ({1}) VALUES ({2})".SFormat(EscapeTableName(table), sbnames, sbvalues);
}
///
/// Builds the SQL WHERE clause
///
///
///
protected static string BuildWhere(List wheres) => wheres.Count > 0
? string.Empty
: "WHERE {0}".SFormat(string.Join(", ", wheres.Select(v => $"{v.Name} = {v.Value}")));
}