178 lines
5.1 KiB
C#
Executable File
178 lines
5.1 KiB
C#
Executable File
using ZB.MOM.WW.CBDD.Core.Storage;
|
|
using ZB.MOM.WW.CBDD.Core.Indexing;
|
|
using ZB.MOM.WW.CBDD.Bson;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.CBDD.Tests;
|
|
|
|
public class QueryPrimitivesTests : IDisposable
|
|
{
|
|
private readonly string _testFile;
|
|
private readonly StorageEngine _storage;
|
|
private readonly BTreeIndex _index;
|
|
|
|
public QueryPrimitivesTests()
|
|
{
|
|
_testFile = Path.Combine(Path.GetTempPath(), $"docdb_test_{Guid.NewGuid()}.db");
|
|
_storage = new StorageEngine(_testFile, PageFileConfig.Default);
|
|
|
|
// Initialize simple index
|
|
var options = IndexOptions.CreateBTree("test");
|
|
_index = new BTreeIndex(_storage, options);
|
|
|
|
SeedData();
|
|
}
|
|
|
|
private void SeedData()
|
|
{
|
|
// Insert keys: 10, 20, 30, 40, 50
|
|
// And strings: "A", "AB", "ABC", "B", "C"
|
|
|
|
var txnId = _storage.BeginTransaction().TransactionId;
|
|
|
|
Insert(10, txnId);
|
|
Insert(20, txnId);
|
|
Insert(30, txnId);
|
|
Insert(40, txnId);
|
|
Insert(50, txnId);
|
|
|
|
Insert("A", txnId);
|
|
Insert("AB", txnId);
|
|
Insert("ABC", txnId);
|
|
Insert("B", txnId);
|
|
Insert("C", txnId);
|
|
|
|
_storage.CommitTransaction(txnId);
|
|
}
|
|
|
|
private void Insert(dynamic value, ulong txnId)
|
|
{
|
|
IndexKey key;
|
|
if (value is int i) key = IndexKey.Create(i);
|
|
else if (value is string s) key = IndexKey.Create(s);
|
|
else throw new ArgumentException();
|
|
|
|
_index.Insert(key, new DocumentLocation(1, 1), txnId);
|
|
}
|
|
|
|
[Fact]
|
|
public void Equal_ShouldFindExactMatch()
|
|
{
|
|
var key = IndexKey.Create(30);
|
|
var result = _index.Equal(key, 0).ToList();
|
|
|
|
result.Count().ShouldBe(1);
|
|
result[0].Key.ShouldBe(key);
|
|
}
|
|
|
|
[Fact]
|
|
public void Equal_ShouldReturnEmpty_WhenNotFound()
|
|
{
|
|
var key = IndexKey.Create(25);
|
|
var result = _index.Equal(key, 0).ToList();
|
|
|
|
result.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void GreaterThan_ShouldReturnMatches()
|
|
{
|
|
var key = IndexKey.Create(30);
|
|
var result = _index.GreaterThan(key, orEqual: false, 0).ToList();
|
|
|
|
(result.Count >= 2).ShouldBeTrue();
|
|
result[0].Key.ShouldBe(IndexKey.Create(40));
|
|
result[1].Key.ShouldBe(IndexKey.Create(50));
|
|
}
|
|
|
|
[Fact]
|
|
public void GreaterThanOrEqual_ShouldReturnMatches()
|
|
{
|
|
var key = IndexKey.Create(30);
|
|
var result = _index.GreaterThan(key, orEqual: true, 0).ToList();
|
|
|
|
(result.Count >= 3).ShouldBeTrue();
|
|
result[0].Key.ShouldBe(IndexKey.Create(30));
|
|
result[1].Key.ShouldBe(IndexKey.Create(40));
|
|
result[2].Key.ShouldBe(IndexKey.Create(50));
|
|
}
|
|
|
|
[Fact]
|
|
public void LessThan_ShouldReturnMatches()
|
|
{
|
|
var key = IndexKey.Create(30);
|
|
var result = _index.LessThan(key, orEqual: false, 0).ToList();
|
|
|
|
result.Count.ShouldBe(2); // 20, 10 (Order is backward?)
|
|
// LessThan yields backward?
|
|
// Implementation: MovePrev(). So yes, 20 then 10.
|
|
result[0].Key.ShouldBe(IndexKey.Create(20));
|
|
result[1].Key.ShouldBe(IndexKey.Create(10));
|
|
}
|
|
|
|
[Fact]
|
|
public void Between_ShouldReturnRange()
|
|
{
|
|
var start = IndexKey.Create(20);
|
|
var end = IndexKey.Create(40);
|
|
var result = _index.Between(start, end, startInclusive: true, endInclusive: true, 0).ToList();
|
|
|
|
result.Count.ShouldBe(3); // 20, 30, 40
|
|
result[0].Key.ShouldBe(IndexKey.Create(20));
|
|
result[1].Key.ShouldBe(IndexKey.Create(30));
|
|
result[2].Key.ShouldBe(IndexKey.Create(40));
|
|
}
|
|
|
|
[Fact]
|
|
public void StartsWith_ShouldReturnPrefixMatches()
|
|
{
|
|
var result = _index.StartsWith("AB", 0).ToList();
|
|
|
|
result.Count.ShouldBe(2); // AB, ABC
|
|
result[0].Key.ShouldBe(IndexKey.Create("AB"));
|
|
result[1].Key.ShouldBe(IndexKey.Create("ABC"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Like_ShouldSupportWildcards()
|
|
{
|
|
// "A%" -> A, AB, ABC
|
|
var result = _index.Like("A%", 0).ToList();
|
|
result.Count.ShouldBe(3);
|
|
|
|
// "%B%" -> AB, ABC, B
|
|
var result2 = _index.Like("%B%", 0).ToList();
|
|
// A (no), AB (yes), ABC (yes), B (yes), C (no)
|
|
result2.Count.ShouldBe(3); // AB, ABC, B. Wait, order?
|
|
// Index order: A, AB, ABC, B, C.
|
|
// AB ok. ABC ok. B ok.
|
|
}
|
|
|
|
[Fact]
|
|
public void Like_Underscore_ShouldMatchSingleChar()
|
|
{
|
|
// "_B" -> AB (yes), B (no: len 1), ABC (no)
|
|
var result = _index.Like("_B", 0).ToList();
|
|
result.Count().ShouldBe(1);
|
|
result[0].Key.ShouldBe(IndexKey.Create("AB"));
|
|
}
|
|
|
|
[Fact]
|
|
public void In_ShouldReturnSpecificKeys()
|
|
{
|
|
var keys = new[] { IndexKey.Create(10), IndexKey.Create(30), IndexKey.Create(50), IndexKey.Create(99) };
|
|
var result = _index.In(keys, 0).ToList();
|
|
|
|
result.Count.ShouldBe(3); // 10, 30, 50. (99 missing)
|
|
result[0].Key.ShouldBe(IndexKey.Create(10));
|
|
result[1].Key.ShouldBe(IndexKey.Create(30));
|
|
result[2].Key.ShouldBe(IndexKey.Create(50));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_storage.Dispose();
|
|
File.Delete(_testFile);
|
|
}
|
|
}
|