using ZB.MOM.WW.CBDD.Core.Indexing;
using ZB.MOM.WW.CBDD.Core.Storage;
using ZB.MOM.WW.CBDD.Shared;
using ZB.MOM.WW.CBDD.Shared.TestDbContext_TestDbContext_Mappers;
namespace ZB.MOM.WW.CBDD.Tests;
public class CollectionIndexManagerAndDefinitionTests
{
///
/// Tests find best index should prefer unique index.
///
[Fact]
public void FindBestIndex_Should_Prefer_Unique_Index()
{
var dbPath = NewDbPath();
try
{
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
var mapper = new ZB_MOM_WW_CBDD_Shared_PersonMapper();
using var manager = new CollectionIndexManager(storage, mapper, "people_idx_pref_unique");
manager.CreateIndex(p => p.Age, name: "idx_age", unique: false);
manager.CreateIndex(p => p.Age, name: "idx_age_unique", unique: true);
var best = manager.FindBestIndex("Age");
best.ShouldNotBeNull();
best.Definition.Name.ShouldBe("idx_age_unique");
best.Definition.IsUnique.ShouldBeTrue();
}
finally
{
CleanupFiles(dbPath);
}
}
///
/// Tests find best compound index should choose longest prefix.
///
[Fact]
public void FindBestCompoundIndex_Should_Choose_Longest_Prefix()
{
var dbPath = NewDbPath();
try
{
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
var mapper = new ZB_MOM_WW_CBDD_Shared_PersonMapper();
using var manager = new CollectionIndexManager(storage, mapper, "people_idx_compound");
manager.CreateIndex(new CollectionIndexDefinition(
"idx_name",
["Name"],
p => p.Name));
manager.CreateIndex(new CollectionIndexDefinition(
"idx_name_age",
["Name", "Age"],
p => new { p.Name, p.Age }));
manager.CreateIndex(new CollectionIndexDefinition(
"idx_name_age_id",
["Name", "Age", "Id"],
p => new { p.Name, p.Age, p.Id }));
var best = manager.FindBestCompoundIndex(["Name", "Age"]);
best.ShouldNotBeNull();
best.Definition.Name.ShouldBe("idx_name_age_id");
best.Definition.PropertyPaths.Length.ShouldBe(3);
}
finally
{
CleanupFiles(dbPath);
}
}
///
/// Tests drop index should remove metadata and be idempotent.
///
[Fact]
public void DropIndex_Should_Remove_Metadata_And_Be_Idempotent()
{
var dbPath = NewDbPath();
const string collectionName = "people_idx_drop";
try
{
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
var mapper = new ZB_MOM_WW_CBDD_Shared_PersonMapper();
using (var manager = new CollectionIndexManager(storage, mapper, collectionName))
{
manager.CreateIndex(p => p.Age, name: "idx_age", unique: false);
manager.DropIndex("idx_age").ShouldBeTrue();
manager.DropIndex("idx_age").ShouldBeFalse();
manager.GetIndexInfo().ShouldBeEmpty();
}
using var reloaded = new CollectionIndexManager(storage, mapper, collectionName);
reloaded.GetIndexInfo().ShouldBeEmpty();
}
finally
{
CleanupFiles(dbPath);
}
}
///
/// Tests collection index definition should respect query support rules.
///
[Fact]
public void CollectionIndexDefinition_Should_Respect_Query_Support_Rules()
{
var definition = new CollectionIndexDefinition(
"idx_name_age",
["Name", "Age"],
p => new { p.Name, p.Age });
definition.CanSupportQuery("Name").ShouldBeTrue();
definition.CanSupportQuery("Age").ShouldBeFalse();
definition.CanSupportCompoundQuery(["Name"]).ShouldBeTrue();
definition.CanSupportCompoundQuery(["Name", "Age"]).ShouldBeTrue();
definition.CanSupportCompoundQuery(["Name", "Age", "Id"]).ShouldBeFalse();
definition.ToString().ShouldContain("idx_name_age");
definition.ToString().ShouldContain("Name");
}
///
/// Tests collection index info to string should include diagnostics.
///
[Fact]
public void CollectionIndexInfo_ToString_Should_Include_Diagnostics()
{
var info = new CollectionIndexInfo
{
Name = "idx_age",
PropertyPaths = ["Age"],
EstimatedDocumentCount = 12,
EstimatedSizeBytes = 4096
};
var text = info.ToString();
text.ShouldContain("idx_age");
text.ShouldContain("Age");
text.ShouldContain("12 docs");
}
private static string NewDbPath()
=> Path.Combine(Path.GetTempPath(), $"idx_mgr_{Guid.NewGuid():N}.db");
private static void CleanupFiles(string dbPath)
{
if (File.Exists(dbPath)) File.Delete(dbPath);
var walPath = Path.ChangeExtension(dbPath, ".wal");
if (File.Exists(walPath)) File.Delete(walPath);
var altWalPath = dbPath + "-wal";
if (File.Exists(altWalPath)) File.Delete(altWalPath);
}
}