Skip to content

Commit

Permalink
[Database] Query generator improvements: bulk insert, 'try' operations
Browse files Browse the repository at this point in the history
  • Loading branch information
BAndysc committed Aug 6, 2023
1 parent 7b48948 commit 567304d
Show file tree
Hide file tree
Showing 62 changed files with 1,738 additions and 292 deletions.
39 changes: 35 additions & 4 deletions DatabaseTester/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
using WDE.DatabaseEditors.Factories;
using WDE.DatabaseEditors.Loaders;
using WDE.DatabaseEditors.Services;
using WDE.Module;
using WDE.MySqlDatabaseCommon.Database;
using WDE.MySqlDatabaseCommon.Providers;
using WDE.MySqlDatabaseCommon.Services;
using WDE.QueryGenerators;
using WDE.QueryGenerators.Base;
using WDE.SqlInterpreter;
using WDE.SqlQueryGenerator;
using WDE.Trinity;
using WDE.TrinityMySqlDatabase;
using WDE.TrinityMySqlDatabase.Data;
Expand Down Expand Up @@ -138,6 +141,19 @@ public static async Task<int> Test<T>(string[] args, params ICoreVersion[] cores


var ioc = new UnityContainer().AddExtension(new Diagnostic());

var queryGenerators = typeof(T).Assembly.GetTypes()
.Where(type => type.GetInterfaces().Where(i => i.IsGenericType)
.Select(i => i.GetGenericTypeDefinition())
.Any(i => i == typeof(IInsertQueryProvider<>) ||
i == typeof(IDeleteQueryProvider<>) ||
i == typeof(IUpdateQueryProvider<>)));
foreach (var queryGenerator in queryGenerators)
{
foreach (var @interface in queryGenerator.GetInterfaces())
ioc.RegisterSingleton(@interface, queryGenerator);
}

ioc.RegisterInstance<IContainerProvider>(new UnityContainerProvider(ioc));
ioc.RegisterInstance<IMessageBoxService>(new ConsoleMessageBoxService());
ioc.RegisterInstance<IWorldDatabaseSettingsProvider>(dbSettings);
Expand All @@ -149,6 +165,7 @@ public static async Task<int> Test<T>(string[] args, params ICoreVersion[] cores
ioc.RegisterInstance<ITaskRunner>(new SyncTaskRunner());
ioc.RegisterInstance<IStatusBar>(Substitute.For<IStatusBar>());
ioc.RegisterInstance<IParameterFactory>(Substitute.For<IParameterFactory>());
ioc.RegisterInstance<IUserSettings>(Substitute.For<IUserSettings>());

ioc.RegisterInstance<IMySqlWorldConnectionStringProvider>(databaseConn);
ioc.RegisterInstance<IMainThread>(new SyncMainThread());
Expand All @@ -169,7 +186,7 @@ public static async Task<int> Test<T>(string[] args, params ICoreVersion[] cores
var queryGeneratorModule = new QueryGeneratorModule();
queryGeneratorModule.InitializeCore(core.Tag);
queryGeneratorModule.RegisterTypes(new UnityContainerRegistry(ioc));

var worldDb = ioc.Resolve<T>();
ioc.RegisterInstance<IDatabaseProvider>(worldDb);
ioc.RegisterInstance<ICachedDatabaseProvider>(worldDb);
Expand All @@ -193,11 +210,22 @@ public static async Task<int> Test<T>(string[] args, params ICoreVersion[] cores
await executor.ExecuteSql($"ALTER TABLE `{tableName}` ENGINE = InnoDB");
}

foreach (var query in tester.Generate().Where(x => x != null))
foreach (var queryGenerator in tester.Generate())
{
IQuery query;
try
{
await executor.ExecuteSql(query!);
query = queryGenerator();
}
catch (TableNotSupportedException e)
{
Console.WriteLine("Skipping table: " + e.TableName + " because it is not supported by the selected core.");
continue;
}

try
{
await executor.ExecuteSql(query, true);
}
catch (Exception e)
{
Expand Down Expand Up @@ -247,12 +275,15 @@ public static async Task<int> Test<T>(string[] args, params ICoreVersion[] cores
await worldDb.FindSmartScriptLinesBy(new (IDatabaseProvider.SmartLinePropertyType what, int whatValue, int parameterIndex, long valueToSearch)[] { (IDatabaseProvider.SmartLinePropertyType.Action, 0, 0, 0) });

foreach (var type in Enum.GetValues<EventScriptType>())
{
Console.WriteLine($"GetEventScript({type})");
await worldDb.GetEventScript(type, 0);
}

return 0;
}

private static void FixCurrentDirectory()
public static void FixCurrentDirectory()
{
var path = Assembly.GetExecutingAssembly().Location;
if (string.IsNullOrEmpty(path))
Expand Down
125 changes: 101 additions & 24 deletions DatabaseTester/QueryGeneratorTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,28 @@ public class QueryGeneratorTester
private readonly IQueryGenerator<QuestChainDiff> questChain;
private readonly IQueryGenerator<CreatureDiff> creatureDiff;
private readonly IQueryGenerator<GameObjectDiff> gameobjectDiff;
private readonly IQueryGenerator<ICreatureText> creatureText;
private readonly IQueryGenerator<IGossipMenuOption> gossipMenuOption;
private readonly IQueryGenerator<IGossipMenuLine> gossipMenu;
private readonly IQueryGenerator<CreatureGossipUpdate> creatureTemplateDiff;
private readonly IQueryGenerator<IPointOfInterest> pointOfInterest;
private readonly IQueryGenerator<INpcTextFull> npcTextInsert;
private readonly IQueryGenerator<INpcText> npcTextDelete;

public QueryGeneratorTester(IQueryGenerator<CreatureSpawnModelEssentials> creature,
IQueryGenerator<GameObjectSpawnModelEssentials> gameobject,
IQueryGenerator<ISpawnGroupTemplate> spawnGroupTemplate,
IQueryGenerator<ISpawnGroupSpawn> spawnGroupSpawn,
IQueryGenerator<QuestChainDiff> questChain,
IQueryGenerator<CreatureDiff> creatureDiff,
IQueryGenerator<GameObjectDiff> gameobjectDiff)
IQueryGenerator<GameObjectDiff> gameobjectDiff,
IQueryGenerator<ICreatureText> creatureText,
IQueryGenerator<IGossipMenuOption> gossipMenuOption,
IQueryGenerator<IGossipMenuLine> gossipMenu,
IQueryGenerator<CreatureGossipUpdate> creatureTemplateDiff,
IQueryGenerator<IPointOfInterest> pointOfInterest,
IQueryGenerator<INpcTextFull> npcTextInsert,
IQueryGenerator<INpcText> npcTextDelete)
{
this.creature = creature;
this.gameobject = gameobject;
Expand All @@ -31,6 +45,13 @@ public QueryGeneratorTester(IQueryGenerator<CreatureSpawnModelEssentials> creatu
this.questChain = questChain;
this.creatureDiff = creatureDiff;
this.gameobjectDiff = gameobjectDiff;
this.creatureText = creatureText;
this.gossipMenuOption = gossipMenuOption;
this.gossipMenu = gossipMenu;
this.creatureTemplateDiff = creatureTemplateDiff;
this.pointOfInterest = pointOfInterest;
this.npcTextInsert = npcTextInsert;
this.npcTextDelete = npcTextDelete;
}

public IEnumerable<string?> Tables()
Expand All @@ -39,64 +60,120 @@ public QueryGeneratorTester(IQueryGenerator<CreatureSpawnModelEssentials> creatu
yield return gameobject.TableName;
yield return spawnGroupTemplate.TableName;
yield return spawnGroupSpawn.TableName;
yield return creatureText.TableName;
yield return gossipMenuOption.TableName;
yield return gossipMenu.TableName;
yield return creatureTemplateDiff.TableName;
yield return pointOfInterest.TableName;
yield return npcTextInsert.TableName;
}

public IEnumerable<IQuery?> Generate()
public IEnumerable<Func<IQuery>> Generate()
{
yield return creature.Insert(new CreatureSpawnModelEssentials()
yield return () => gossipMenuOption.Insert(new AbstractGossipMenuOption()
{
Guid = int.MaxValue - 1
MenuId = 1,
});
yield return gameobject.Insert(new GameObjectSpawnModelEssentials()
yield return () => gossipMenuOption.Delete(new AbstractGossipMenuOption()
{
Guid = int.MaxValue - 1
MenuId = 1
});
yield return creature.Delete(new CreatureSpawnModelEssentials()
yield return () => gossipMenu.Insert(new AbstractGossipMenuLine()
{
Guid = int.MaxValue - 1
MenuId = 1,
});
yield return gameobject.Delete(new GameObjectSpawnModelEssentials()
yield return () => gossipMenu.Delete(new AbstractGossipMenuLine()
{
Guid = int.MaxValue - 1
MenuId = 1
});
yield return () => creature.Insert(new CreatureSpawnModelEssentials()
{
Guid = 0xFFFFFF - 1,
Entry = 1
});
yield return () => creatureDiff.Update(new CreatureDiff()
{
Guid = 0xFFFFFF - 1,
Position = Vector3.Zero,
Orientation = 0
});
yield return () => gameobject.Insert(new GameObjectSpawnModelEssentials()
{
Guid = 0xFFFFFF - 1,
Entry = 29
});
yield return () => creature.Delete(new CreatureSpawnModelEssentials()
{
Guid = 0xFFFFFF - 1
});
yield return () => gameobjectDiff.Update(new GameObjectDiff()
{
Guid = 0xFFFFFF - 1,
Position = Vector3.Zero,
Orientation = 0,
Rotation = Quaternion.Identity
});
yield return () => gameobject.Delete(new GameObjectSpawnModelEssentials()
{
Guid = 0xFFFFFF - 1
});
yield return spawnGroupTemplate.Insert(new AbstractSpawnGroupTemplate()
yield return () => spawnGroupTemplate.Insert(new AbstractSpawnGroupTemplate()
{
Id = int.MaxValue - 1
});
yield return spawnGroupSpawn.Insert(new AbstractSpawnGroupSpawn()
yield return () => spawnGroupSpawn.Insert(new AbstractSpawnGroupSpawn()
{
TemplateId = int.MaxValue - 1,
Guid = int.MaxValue - 1
});
yield return spawnGroupTemplate.Delete(new AbstractSpawnGroupTemplate()
yield return () => spawnGroupTemplate.Delete(new AbstractSpawnGroupTemplate()
{
Id = int.MaxValue - 1
});
yield return spawnGroupSpawn.Delete(new AbstractSpawnGroupSpawn()
yield return () => spawnGroupSpawn.Delete(new AbstractSpawnGroupSpawn()
{
TemplateId = int.MaxValue - 1,
Guid = int.MaxValue - 1
});
yield return questChain.Update(new QuestChainDiff()
yield return () => questChain.Update(new QuestChainDiff()
{
Id = int.MaxValue - 1,
BreadcrumbQuestId = 1,
ExclusiveGroup = -2,
NextQuestId = 3,
PrevQuestId = -1
});
yield return creatureDiff.Update(new CreatureDiff()
yield return () => creatureText.Insert(new AbstractCreatureText()
{
Guid = int.MaxValue - 1,
Position = Vector3.Zero,
Orientation = 0
CreatureId = 1,
GroupId = byte.MaxValue - 1,
Id = byte.MaxValue - 1,
Text = "abc"
});
yield return gameobjectDiff.Update(new GameObjectDiff()
yield return () => creatureText.Delete(new AbstractCreatureText()
{
Guid = int.MaxValue - 1,
Position = Vector3.Zero,
Orientation = 0,
Rotation = Quaternion.Identity
CreatureId = 0xFFFFFF - 1
});
yield return () => creatureTemplateDiff.Update(new CreatureGossipUpdate()
{
Entry = 1,
GossipMenuId = 1
});
yield return () => pointOfInterest.Insert(new AbstractPointOfInterest()
{
Id = 0xFFFFFF - 1
});
yield return () => pointOfInterest.Delete(new AbstractPointOfInterest()
{
Id = 0xFFFFFF - 1
});
yield return () => npcTextInsert.Insert(new AbstractNpcTextFull()
{
Id = 0xFFFFFF - 10
});
yield return () => npcTextDelete.Delete(new AbstractNpcText()
{
Id = 0xFFFFFF - 10
});
}
}
20 changes: 20 additions & 0 deletions Modules/WDE.QueryGenerators/Base/BaseInsertQueryProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using WDE.SqlQueryGenerator;

namespace WDE.QueryGenerators.Base;

public abstract class BaseInsertQueryProvider<T> : IInsertQueryProvider<T>
{
public IQuery Insert(T t)
{
return Queries.Table(TableName).Insert(Convert(t));
}

public IQuery BulkInsert(IReadOnlyCollection<T> collection)
{
return Queries.Table(TableName).BulkInsert(collection.Select(Convert));
}

protected abstract object Convert(T obj);

public abstract string TableName { get; }
}
1 change: 1 addition & 0 deletions Modules/WDE.QueryGenerators/Base/IInsertQueryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace WDE.QueryGenerators.Base;
public interface IInsertQueryProvider<T>
{
IQuery Insert(T t);
IQuery BulkInsert(IReadOnlyCollection<T> collection);
string TableName { get; }
int Priority => 0;
}
10 changes: 6 additions & 4 deletions Modules/WDE.QueryGenerators/Base/IQueryGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using WDE.SqlQueryGenerator;
using Extensions = AvaloniaStyles.Controls.Extensions;

namespace WDE.QueryGenerators.Base;

public interface IQueryGenerator<R>
public interface IQueryGenerator<T>
{
IQuery? Insert(R element);
IQuery? Delete(R element);
IQuery? Update(R element);
IQuery? TryInsert(T element);
IQuery? TryBulkInsert(IReadOnlyCollection<T> elements);
IQuery? TryDelete(T element);
IQuery? TryUpdate(T element);
string? TableName { get; }
}
1 change: 1 addition & 0 deletions Modules/WDE.QueryGenerators/Base/IUpdateQueryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ namespace WDE.QueryGenerators.Base;
public interface IUpdateQueryProvider<T>
{
IQuery Update(T diff);
string TableName { get; }
int Priority => 0;
}
29 changes: 29 additions & 0 deletions Modules/WDE.QueryGenerators/Base/NotSupportedQueryProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using WDE.Module.Attributes;
using WDE.SqlQueryGenerator;

namespace WDE.QueryGenerators.Base;

[AutoRegister]
[SingleInstance]
public abstract class NotSupportedQueryProvider<T> : IInsertQueryProvider<T>, IDeleteQueryProvider<T>, IUpdateQueryProvider<T>
{
public abstract string TableName { get; }

public IQuery Insert(T t) => throw new TableNotSupportedException(TableName);

public IQuery BulkInsert(IReadOnlyCollection<T> collection) => throw new TableNotSupportedException(TableName);

public IQuery Delete(T t) => throw new TableNotSupportedException(TableName);

public IQuery Update(T diff) => throw new TableNotSupportedException(TableName);
}

public class TableNotSupportedException : Exception
{
public string TableName { get; }

public TableNotSupportedException(string tableName) : base("Currently selected database doesn't support table " + tableName)
{
TableName = tableName;
}
}
8 changes: 5 additions & 3 deletions Modules/WDE.QueryGenerators/Base/QueryGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ public QueryGenerator(IEnumerable<IInsertQueryProvider<R>> insertProviders,
Console.WriteLine("Couldn't find a provider for " + typeof(R));
}

public IQuery? Insert(R element) => insertProvider?.Insert(element);
public IQuery? Delete(R element) => deleteProvider?.Delete(element);
public IQuery? Update(R element) => updateProvider?.Update(element);
public IQuery? TryInsert(R element) => insertProvider?.Insert(element);
public IQuery? TryBulkInsert(IReadOnlyCollection<R> elements) => insertProvider?.BulkInsert(elements);

public IQuery? TryDelete(R element) => deleteProvider?.Delete(element);
public IQuery? TryUpdate(R element) => updateProvider?.Update(element);

public string? TableName => insertProvider?.TableName;
}
6 changes: 6 additions & 0 deletions Modules/WDE.QueryGenerators/Base/QueryGeneratorException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace WDE.QueryGenerators.Base;

public class QueryGeneratorException<T> : Exception
{
public QueryGeneratorException(string updateName) : base($"{updateName} query generator for " + typeof(T).Name + " not found for selected core version") { }
}
Loading

0 comments on commit 567304d

Please sign in to comment.