Skip to content

Commit 36a2561

Browse files
Add support for collection contains (#15)
1 parent 0f560a8 commit 36a2561

File tree

3 files changed

+73
-56
lines changed

3 files changed

+73
-56
lines changed

.github/workflows/dotnet.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This workflow will build a .NET project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3+
4+
name: .NET
5+
6+
on:
7+
push:
8+
branches: ["main"]
9+
pull_request:
10+
branches: ["main"]
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
- name: Setup .NET
19+
uses: actions/setup-dotnet@v4
20+
with:
21+
dotnet-version: 8.0.x
22+
- name: Restore dependencies
23+
run: dotnet restore
24+
- name: Build
25+
run: dotnet build --no-restore
26+
- name: Test
27+
run: dotnet test --no-build --verbosity normal

src/PgKeyValueDB/SqlExpressionVisitor.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
177177
}
178178
}
179179

180+
// Handle Contains for collections
181+
if (node.Method.Name == nameof(Enumerable.Contains) && node.Arguments.Count == 1)
182+
{
183+
var collection = node.Object;
184+
var item = node.Arguments[0];
185+
186+
if (collection is MemberExpression memberExpression)
187+
{
188+
var parentPath = BuildNestedJsonPath(memberExpression);
189+
whereClause.Append($"jsonb_exists({parentPath}, ");
190+
Visit(item);
191+
whereClause.Append(")");
192+
return node;
193+
}
194+
}
195+
180196
throw new NotSupportedException($"Method {node.Method.Name} is not supported");
181197
}
182198

test/PgKeyValueDB.Tests/PgKeyValueDBTest.cs

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,13 @@ public class PgKeyValueDBTest
4949
{
5050
private static PgServer pg = null!;
5151
private static PgKeyValueDB kv = null!;
52-
private const string TestPid = "AdvancedTest";
53-
private static TestContext testContext = null!;
54-
private static string connectionString = null!;
5552

5653
[ClassInitialize]
5754
public static void ClassInit(TestContext context)
5855
{
59-
testContext = context;
6056
IServiceCollection services = new ServiceCollection();
6157
pg = new PgServer("16.2.0", clearWorkingDirOnStart: true, clearInstanceDirOnStop: true);
6258
pg.Start();
63-
connectionString = $"Host=localhost;Port={pg.PgPort};Username=postgres;Password=postgres;Database=postgres";
6459
services.AddPgKeyValueDB($"Host=localhost;Port={pg.PgPort};Username=postgres;Password=postgres;Database=postgres", b =>
6560
{
6661
b.SchemaName = "pgkeyvaluetest";
@@ -77,57 +72,6 @@ public static void ClassCleanup()
7772
pg?.Dispose();
7873
}
7974

80-
private static async Task SetupTestData()
81-
{
82-
var users = new[]
83-
{
84-
new UserProfile
85-
{
86-
Name = "John Doe",
87-
Age = 30,
88-
Status = UserStatus.Active,
89-
Role = UserRole.Admin,
90-
PrimaryAddress = new Address
91-
{
92-
Street = "123 Main St",
93-
City = "New York",
94-
Country = "USA",
95-
ZipCode = 10001
96-
},
97-
SecondaryAddress = new Address
98-
{
99-
Street = "456 Park Ave",
100-
City = "Boston",
101-
Country = "USA",
102-
ZipCode = 02108
103-
},
104-
Tags = ["vip", "early-adopter"],
105-
IsVerified = true
106-
},
107-
new UserProfile
108-
{
109-
Name = "Jane Smith",
110-
Age = 25,
111-
Status = UserStatus.Pending,
112-
Role = UserRole.User,
113-
PrimaryAddress = new Address
114-
{
115-
Street = "789 Oak Rd",
116-
City = "San Francisco",
117-
Country = "USA",
118-
ZipCode = 94102
119-
},
120-
Tags = ["beta-tester"],
121-
IsVerified = false
122-
}
123-
};
124-
125-
for (int i = 0; i < users.Length; i++)
126-
{
127-
await kv.UpsertAsync($"user_{i}", users[i], TestPid);
128-
}
129-
}
130-
13175
[TestMethod]
13276
public void BasicTest()
13377
{
@@ -561,4 +505,34 @@ public async Task FilterWithStringParameterTest()
561505
Assert.IsTrue(results.Any(u => u.Name == "John Smith"));
562506
Assert.IsTrue(results.Any(u => u.DisplayName == "Johnny"));
563507
}
508+
509+
[TestMethod]
510+
public async Task FilterByTagTest()
511+
{
512+
var key1 = nameof(FilterByTagTest) + "1";
513+
var key2 = nameof(FilterByTagTest) + "2";
514+
var pid = nameof(FilterByTagTest);
515+
516+
var user1 = new UserProfile
517+
{
518+
Name = "Alice",
519+
Tags = new List<string> { "vip", "early-adopter" }
520+
};
521+
522+
var user2 = new UserProfile
523+
{
524+
Name = "Bob",
525+
Tags = new List<string> { "regular", "new-user" }
526+
};
527+
528+
await kv.UpsertAsync(key1, user1, pid);
529+
await kv.UpsertAsync(key2, user2, pid);
530+
531+
// This query should filter users by the "vip" tag
532+
Expression<Func<UserProfile, bool>> expr = u => u.Tags!.Contains("vip");
533+
var vipUsers = await kv.GetListAsync(pid, expr).ToListAsync();
534+
535+
Assert.AreEqual(1, vipUsers.Count);
536+
Assert.AreEqual("Alice", vipUsers[0].Name);
537+
}
564538
}

0 commit comments

Comments
 (0)