using Xunit; using ZB.MOM.WW.CBDD.Core.Query; using ZB.MOM.WW.CBDD.Core.Indexing; using System.Linq.Expressions; using System.Collections.Generic; using System; namespace ZB.MOM.WW.CBDD.Tests { public class IndexOptimizationTests { public class TestEntity { public int Id { get; set; } public string Name { get; set; } = ""; public int Age { get; set; } } [Fact] public void Optimizer_Identifies_Equality() { var indexes = new List { new CollectionIndexInfo { Name = "idx_age", PropertyPaths = ["Age"] } }; Expression> predicate = x => x.Age == 30; var model = new QueryModel { WhereClause = predicate }; var result = IndexOptimizer.TryOptimize(model, indexes); result.ShouldNotBeNull(); result.IndexName.ShouldBe("idx_age"); result.MinValue.ShouldBe(30); result.MaxValue.ShouldBe(30); result.IsRange.ShouldBeFalse(); } [Fact] public void Optimizer_Identifies_Range_GreaterThan() { var indexes = new List { new CollectionIndexInfo { Name = "idx_age", PropertyPaths = ["Age"] } }; Expression> predicate = x => x.Age > 25; var model = new QueryModel { WhereClause = predicate }; var result = IndexOptimizer.TryOptimize(model, indexes); result.ShouldNotBeNull(); result.IndexName.ShouldBe("idx_age"); result.MinValue.ShouldBe(25); result.MaxValue.ShouldBeNull(); result.IsRange.ShouldBeTrue(); } [Fact] public void Optimizer_Identifies_Range_LessThan() { var indexes = new List { new CollectionIndexInfo { Name = "idx_age", PropertyPaths = ["Age"] } }; Expression> predicate = x => x.Age < 50; var model = new QueryModel { WhereClause = predicate }; var result = IndexOptimizer.TryOptimize(model, indexes); result.ShouldNotBeNull(); result.IndexName.ShouldBe("idx_age"); result.MinValue.ShouldBeNull(); result.MaxValue.ShouldBe(50); result.IsRange.ShouldBeTrue(); } [Fact] public void Optimizer_Identifies_Range_Between_Simulated() { var indexes = new List { new CollectionIndexInfo { Name = "idx_age", PropertyPaths = ["Age"] } }; Expression> predicate = x => x.Age > 20 && x.Age < 40; var model = new QueryModel { WhereClause = predicate }; var result = IndexOptimizer.TryOptimize(model, indexes); result.ShouldNotBeNull(); result.IndexName.ShouldBe("idx_age"); result.MinValue.ShouldBe(20); result.MaxValue.ShouldBe(40); result.IsRange.ShouldBeTrue(); } [Fact] public void Optimizer_Identifies_StartsWith() { var indexes = new List { new CollectionIndexInfo { Name = "idx_name", PropertyPaths = ["Name"], Type = IndexType.BTree } }; Expression> predicate = x => x.Name.StartsWith("Ali"); var model = new QueryModel { WhereClause = predicate }; var result = IndexOptimizer.TryOptimize(model, indexes); result.ShouldNotBeNull(); result.IndexName.ShouldBe("idx_name"); result.MinValue.ShouldBe("Ali"); // "Ali" + next char -> "Alj" result.MaxValue.ShouldBe("Alj"); result.IsRange.ShouldBeTrue(); } [Fact] public void Optimizer_Ignores_NonIndexed_Fields() { var indexes = new List { new CollectionIndexInfo { Name = "idx_age", PropertyPaths = ["Age"] } }; Expression> predicate = x => x.Name == "Alice"; // Name is not indexed var model = new QueryModel { WhereClause = predicate }; var result = IndexOptimizer.TryOptimize(model, indexes); result.ShouldBeNull(); } } }