Skip to content

Commit b0850c2

Browse files
Handle conversion in BuildNestedJsonPath (#20)
* Add complex expression test with inheritance that works and with interface inheritance that do not work. * Handle conversion in BuildNestedJsonPath --------- Co-authored-by: Anders Revsgaard <[email protected]>
1 parent 65d72c7 commit b0850c2

File tree

3 files changed

+122
-6
lines changed

3 files changed

+122
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
bin
22
obj
33
.vscode
4+
/.vs/*

src/PgKeyValueDB/SqlExpressionVisitor.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node)
119119
}
120120

121121
Visit(node.Object);
122-
whereClause.Append(isCaseInsensitive ? " ILIKE " : " like ");
122+
whereClause.Append(isCaseInsensitive ? " ilike " : " like ");
123123

124124
// Get the search value and create pattern parameter
125125
var searchValue = Expression.Lambda(node.Arguments[0]).Compile().DynamicInvoke()?.ToString();
@@ -226,7 +226,7 @@ private string BuildJsonPath(MemberInfo member, string parentPath = "value")
226226
var name = propertyNamingPolicy.ConvertName(member.Name);
227227
if (parentPath != "value")
228228
{
229-
return $"({parentPath} ->> '{name}'){cast}";
229+
return $"({parentPath}->>'{name}'){cast}";
230230
}
231231
return $"(value ->> '{name}'){cast}";
232232
}
@@ -293,6 +293,11 @@ private string BuildNestedJsonPath(MemberExpression expression)
293293
path.Push(current.Member.Name);
294294
break;
295295
}
296+
else if (current.Expression?.NodeType == ExpressionType.Convert)
297+
{
298+
path.Push(current.Member.Name);
299+
break;
300+
}
296301
else if (current.Expression is MemberExpression parent)
297302
{
298303
path.Push(current.Member.Name);
@@ -306,7 +311,7 @@ private string BuildNestedJsonPath(MemberExpression expression)
306311
foreach (var segment in path.Reverse())
307312
{
308313
var name = propertyNamingPolicy.ConvertName(segment);
309-
jsonPath = $"({jsonPath} -> '{name}')";
314+
jsonPath = $"({jsonPath}->'{name}')";
310315
}
311316
return jsonPath;
312317
}

test/PgKeyValueDB.Tests/PgKeyValueDBTest.cs

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ public class Address
2626
public int ZipCode { get; set; }
2727
}
2828

29-
public class UserProfile
29+
public class UserProfile : UserProfileBase1
3030
{
31-
public string? Id { get; set; } // Add this line
31+
public override string? Id { get; set; } // Add this line
3232
public string? Name { get; set; }
3333
public string? DisplayName { get; set; }
3434
public int Age { get; set; }
@@ -38,7 +38,25 @@ public class UserProfile
3838
public Address? SecondaryAddress { get; set; }
3939
public List<string>? Tags { get; set; }
4040
public bool? IsVerified { get; set; }
41-
public List<string>? AdditionalIds { get; set; } // Add this line
41+
public override List<string>? AdditionalIds { get; set; } // Add this line
42+
}
43+
44+
public abstract class UserProfileBase1 : UserProfileBase2, IUserProfileBase1
45+
{ }
46+
47+
public abstract class UserProfileBase2 : IUserProfileBase2
48+
{
49+
public abstract string? Id { get; set; } // Add this line
50+
public virtual List<string>? AdditionalIds { get; set; } // Add this line
51+
}
52+
53+
public interface IUserProfileBase1 : IUserProfileBase2
54+
{ }
55+
56+
public interface IUserProfileBase2
57+
{
58+
string? Id { get; set; } // Add this line
59+
List<string>? AdditionalIds { get; set; } // Add this line
4260
}
4361

4462
public class Poco
@@ -590,4 +608,96 @@ public async Task ComplexExpressionTest()
590608
Assert.AreEqual(1, users.Count);
591609
Assert.AreEqual("Alice", users[0].Name);
592610
}
611+
612+
[TestMethod]
613+
public async Task ComplexExpressionInheritanceTest()
614+
{
615+
var key1 = nameof(ComplexExpressionTest) + "1";
616+
var key2 = nameof(ComplexExpressionTest) + "2";
617+
var pid = nameof(ComplexExpressionTest);
618+
619+
var user1 = new UserProfile
620+
{
621+
Id = "user1",
622+
Name = "Alice",
623+
AdditionalIds = new List<string> { "id1", "id2" }
624+
};
625+
626+
var user2 = new UserProfile
627+
{
628+
Id = "user2",
629+
Name = "Bob",
630+
AdditionalIds = new List<string> { "id3", "id4" }
631+
};
632+
633+
await kv.UpsertAsync(key1, user1, pid);
634+
await kv.UpsertAsync(key2, user2, pid);
635+
636+
// Variables for the expression
637+
bool notIdIsEmpty = false;
638+
string notId = "user3";
639+
string idOrAdditionalId = "id1";
640+
641+
// This query should filter users by the complex expression
642+
List<UserProfile> users = await QueryByBase<UserProfile>(pid, notIdIsEmpty, notId, idOrAdditionalId);
643+
644+
Assert.AreEqual(1, users.Count);
645+
Assert.AreEqual("Alice", users[0].Name);
646+
}
647+
648+
private static async Task<List<T>> QueryByBase<T>(string pid, bool notIdIsEmpty, string notId, string idOrAdditionalId) where T : UserProfileBase1
649+
{
650+
Expression<Func<T, bool>> expr = q =>
651+
(notIdIsEmpty || q.Id != notId) &&
652+
(q.Id == idOrAdditionalId || q.AdditionalIds!.Contains(idOrAdditionalId));
653+
654+
var users = await kv.GetListAsync(pid, expr).ToListAsync();
655+
return users;
656+
}
657+
658+
[TestMethod]
659+
public async Task ComplexExpressionInterfaceInheritanceTest()
660+
{
661+
var key1 = nameof(ComplexExpressionTest) + "1";
662+
var key2 = nameof(ComplexExpressionTest) + "2";
663+
var pid = nameof(ComplexExpressionTest);
664+
665+
var user1 = new UserProfile
666+
{
667+
Id = "user1",
668+
Name = "Alice",
669+
AdditionalIds = new List<string> { "id1", "id2" }
670+
};
671+
672+
var user2 = new UserProfile
673+
{
674+
Id = "user2",
675+
Name = "Bob",
676+
AdditionalIds = new List<string> { "id3", "id4" }
677+
};
678+
679+
await kv.UpsertAsync(key1, user1, pid);
680+
await kv.UpsertAsync(key2, user2, pid);
681+
682+
// Variables for the expression
683+
bool notIdIsEmpty = false;
684+
string notId = "user3";
685+
string idOrAdditionalId = "id1";
686+
687+
// This query should filter users by the complex expression
688+
List<UserProfile> users = await QueryByInterfaceBase<UserProfile>(pid, notIdIsEmpty, notId, idOrAdditionalId);
689+
690+
Assert.AreEqual(1, users.Count);
691+
Assert.AreEqual("Alice", users[0].Name);
692+
}
693+
694+
private static async Task<List<T>> QueryByInterfaceBase<T>(string pid, bool notIdIsEmpty, string notId, string idOrAdditionalId) where T : IUserProfileBase1
695+
{
696+
Expression<Func<T, bool>> expr = q =>
697+
(notIdIsEmpty || q.Id != notId) &&
698+
(q.Id == idOrAdditionalId || q.AdditionalIds!.Contains(idOrAdditionalId));
699+
700+
var users = await kv.GetListAsync(pid, expr).ToListAsync();
701+
return users;
702+
}
593703
}

0 commit comments

Comments
 (0)