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
{
///
/// Gets or sets the id.
///
public int Id { get; set; }
///
/// Gets or sets the name.
///
public string Name { get; set; } = "";
///
/// Gets or sets the age.
///
public int Age { get; set; }
}
///
/// Tests optimizer identifies equality.
///
[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();
}
///
/// Tests optimizer identifies range greater than.
///
[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();
}
///
/// Tests optimizer identifies range less than.
///
[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();
}
///
/// Tests optimizer identifies range between simulated.
///
[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();
}
///
/// Tests optimizer identifies starts with.
///
[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();
}
///
/// Tests optimizer ignores non indexed fields.
///
[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();
}
}
}