Skip to content

Commit 68b7e25

Browse files
rube200JKamskercursoragent
authored
Adding EndsWith method for Query and QueryAny (#2727)
* Add Contributor Covenant Code of Conduct This document outlines the Code of Conduct for community members, detailing pledges, standards of behavior, enforcement responsibilities, and consequences for violations. * Update README with new build status and badges Updated build status badge and added pre-release badge. * Adding EndsWith method for Query and QueryAny * Delete CODE_OF_CONDUCT.md * Fix: Correct comment syntax for EndsWith method Co-authored-by: rubegrube <rubegrube@gmail.com> * Update README with AppVeyor build status badge Co-authored-by: rubegrube <rubegrube@gmail.com> * Add tests for Query.StartsWith, Query.EndsWith, and Query.Contains Added unit tests for the string matching query methods in QueryApi_Tests.cs: - Query.StartsWith: Tests filtering by name prefix - Query.EndsWith: Tests filtering by name suffix - Query.Contains: Tests filtering by substring match * Fix Query_Contains test to use specific pattern Use "John" instead of "an" to avoid case-sensitivity differences between LINQ string.Contains() and LiteDB LIKE operator. --------- Co-authored-by: Jonas Kamsker <11245306+JKamsker@users.noreply.github.com> Co-authored-by: Rúben Garcia <rube200@users.noreply.github.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent e55199d commit 68b7e25

4 files changed

Lines changed: 85 additions & 7 deletions

File tree

LiteDB.Tests/Database/MultiKey_Mapper_Tests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ public void MultiKey_Mapper()
6363
col.Count(Query.Any().EQ("Keys", 2)).Should().Be(2);
6464
col.Count(x => x.Keys.Contains(2)).Should().Be(2);
6565

66-
col.Count(Query.Any().StartsWith("Customers[*].Name", "Ana")).Should().Be(2);
67-
col.Count(x => x.Customers.Select(z => z.Name).Any(z => z.StartsWith("Ana"))).Should().Be(2);
66+
col.Count(Query.Any().StartsWith("Customers[*].Name", "An")).Should().Be(2);
67+
col.Count(Query.Any().EndsWith("Customers[*].Name", "na")).Should().Be(2);
68+
col.Count(Query.Any().Contains("Customers[*].Name", "Ana")).Should().Be(2);
69+
col.Count(x => x.Customers.Select(z => z.Name).Any(z => z.StartsWith("An"))).Should().Be(2);
70+
col.Count(x => x.Customers.Select(z => z.Name).Any(z => z.EndsWith("na"))).Should().Be(2);
71+
col.Count(x => x.Customers.Select(z => z.Name).Any(z => z.Contains("Ana"))).Should().Be(2);
6872

6973
col.Count(Query.Any().StartsWith("Customers[*].Name", "D")).Should().Be(1);
7074
col.Count(x => x.Customers.Select(z => z.Name).Any(z => z.StartsWith("D"))).Should().Be(1);

LiteDB.Tests/Query/QueryApi_Tests.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using FluentAssertions;
1+
using FluentAssertions;
22
using System;
33
using System.Linq;
44
using Xunit;
@@ -32,5 +32,45 @@ public void Query_And_Same_Field()
3232

3333
AssertEx.ArrayEqual(r0, r1, true);
3434
}
35+
36+
[Fact]
37+
public void Query_StartsWith()
38+
{
39+
using var db = new PersonQueryData();
40+
var (collection, local) = db.GetData();
41+
42+
var r0 = local.Where(x => x.Name.StartsWith("Jo")).ToArray();
43+
44+
var r1 = collection.Find(Query.StartsWith("Name", "Jo")).ToArray();
45+
46+
AssertEx.ArrayEqual(r0, r1, true);
47+
}
48+
49+
[Fact]
50+
public void Query_EndsWith()
51+
{
52+
using var db = new PersonQueryData();
53+
var (collection, local) = db.GetData();
54+
55+
var r0 = local.Where(x => x.Name.EndsWith("er")).ToArray();
56+
57+
var r1 = collection.Find(Query.EndsWith("Name", "er")).ToArray();
58+
59+
AssertEx.ArrayEqual(r0, r1, true);
60+
}
61+
62+
[Fact]
63+
public void Query_Contains()
64+
{
65+
using var db = new PersonQueryData();
66+
var (collection, local) = db.GetData();
67+
68+
// Use uppercase pattern to avoid case-sensitivity differences between LINQ and LiteDB LIKE
69+
var r0 = local.Where(x => x.Name.Contains("John")).ToArray();
70+
71+
var r1 = collection.Find(Query.Contains("Name", "John")).ToArray();
72+
73+
AssertEx.ArrayEqual(r0, r1, true);
74+
}
3575
}
3676
}

LiteDB/Client/Structures/Query.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using LiteDB.Engine;
1+
using LiteDB.Engine;
22

33
using System;
44
using System.Collections.Generic;
@@ -119,8 +119,20 @@ public static BsonExpression StartsWith(string field, string value)
119119
if (field.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(field));
120120
if (value.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(value));
121121

122-
return BsonExpression.Create($"{field} LIKE {(new BsonValue(value + "%"))}");
122+
return BsonExpression.Create($"{field} LIKE {new BsonValue(value + "%")}");
123123
}
124+
125+
/// <summary>
126+
/// Returns all documents that ends with value (LIKE)
127+
/// </summary>
128+
public static BsonExpression EndsWith(string field, string value)
129+
{
130+
if (field.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(field));
131+
if (value.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(value));
132+
133+
return BsonExpression.Create($"{field} LIKE {new BsonValue("%" + value)}");
134+
}
135+
124136

125137
/// <summary>
126138
/// Returns all documents that contains value (CONTAINS) - string Contains
@@ -130,7 +142,7 @@ public static BsonExpression Contains(string field, string value)
130142
if (field.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(field));
131143
if (value.IsNullOrEmpty()) throw new ArgumentNullException(nameof(value));
132144

133-
return BsonExpression.Create($"{field} LIKE {(new BsonValue("%" + value + "%"))}");
145+
return BsonExpression.Create($"{field} LIKE {new BsonValue("%" + value + "%")}");
134146
}
135147

136148
/// <summary>

LiteDB/Client/Structures/QueryAny.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,31 @@ public BsonExpression StartsWith(string arrayField, string value)
7777
if (arrayField.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(arrayField));
7878
if (value.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(value));
7979

80-
return BsonExpression.Create($"{arrayField} ANY LIKE {(new BsonValue(value + "%"))}");
80+
return BsonExpression.Create($"{arrayField} ANY LIKE {new BsonValue(value + "%")}");
81+
}
82+
83+
/// <summary>
84+
/// Returns all documents for which at least one value in arrayFields ends with value (LIKE)
85+
/// </summary>
86+
public BsonExpression EndsWith(string arrayField, string value)
87+
{
88+
if (arrayField.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(arrayField));
89+
if (value.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(value));
90+
91+
return BsonExpression.Create($"{arrayField} ANY LIKE {new BsonValue("%" + value)}");
8192
}
8293

94+
/// <summary>
95+
/// Returns all documents for which at least one value in arrayFields contains the value (CONTAINS)
96+
/// </summary>
97+
public BsonExpression Contains(string arrayField, string value)
98+
{
99+
if (arrayField.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(arrayField));
100+
if (value.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(value));
101+
102+
return BsonExpression.Create($"{arrayField} ANY LIKE {new BsonValue("%" + value + "%")}");
103+
}
104+
83105
/// <summary>
84106
/// Returns all documents for which at least one value in arrayFields are not equals to value (not equals)
85107
/// </summary>

0 commit comments

Comments
 (0)