Skip to content

Commit e8524f6

Browse files
elexisvenatorjeremydmiller
authored andcommitted
bug fixes and test coverage
1 parent 626a36e commit e8524f6

File tree

4 files changed

+89
-7
lines changed

4 files changed

+89
-7
lines changed

docs/documents/querying/linq/sql.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public async Task query_with_matches_sql()
1818
user.Id.ShouldBe(u.Id);
1919
}
2020
```
21-
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Reading/query_by_sql.cs#L267-L282' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_query_with_matches_sql' title='Start of snippet'>anchor</a></sup>
21+
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Reading/query_by_sql.cs#L336-L351' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_query_with_matches_sql' title='Start of snippet'>anchor</a></sup>
2222
<!-- endSnippet -->
2323

2424
**But**, if you want to take advantage of the more recent and very powerful JSONPath style querying, you will find that using `?` as a placeholder is not suitable, as that character is widely used in JSONPath expressions. If you encounter this issue or write another query where the `?` character is not suitable, you can change the placeholder by providing an alternative. Pass this in before the sql argument.

docs/documents/querying/sql.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ a document body, but in that case you will need to supply the full SQL statement
5454
var sumResults = await session
5555
.QueryAsync<int>("select count(*) from mt_doc_target");
5656
```
57-
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Reading/query_by_sql.cs#L376-L381' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_query_by_full_sql' title='Start of snippet'>anchor</a></sup>
57+
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Reading/query_by_sql.cs#L458-L463' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_query_by_full_sql' title='Start of snippet'>anchor</a></sup>
5858
<!-- endSnippet -->
5959

6060
When querying single JSONB properties into a primitive/value type, you'll need to cast the value to the respective postgres type:
@@ -65,7 +65,7 @@ When querying single JSONB properties into a primitive/value type, you'll need t
6565
var times = await session.QueryAsync<DateTimeOffset>(
6666
"SELECT (data ->> 'ModifiedAt')::timestamptz from mt_doc_user");
6767
```
68-
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Reading/query_by_sql.cs#L330-L335' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using-queryasync-casting' title='Start of snippet'>anchor</a></sup>
68+
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/DocumentDbTests/Reading/query_by_sql.cs#L412-L417' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_using-queryasync-casting' title='Start of snippet'>anchor</a></sup>
6969
<!-- endSnippet -->
7070

7171
The basic rules for how Marten handles user-supplied queries are:

src/DocumentDbTests/Reading/query_by_sql.cs

+83-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.IO;
33
using System.Linq;
44
using System.Threading;
@@ -70,6 +70,31 @@ public async Task stream_query_by_one_parameter()
7070
firstnames[2].ShouldBe("Max");
7171
}
7272

73+
[Fact]
74+
public async Task stream_query_by_one_parameter_custom_placeholder()
75+
{
76+
await using var session = theStore.LightweightSession();
77+
session.Store(new User { FirstName = "Jeremy", LastName = "Miller" });
78+
session.Store(new User { FirstName = "Lindsey", LastName = "Miller" });
79+
session.Store(new User { FirstName = "Max", LastName = "Miller" });
80+
session.Store(new User { FirstName = "Frank", LastName = "Zombo" });
81+
await session.SaveChangesAsync();
82+
83+
var stream = new MemoryStream();
84+
await session.StreamJson<User>(stream, '$', "where data ->> 'LastName' = $", "Miller");
85+
86+
stream.Position = 0;
87+
var results = theStore.Options.Serializer().FromJson<User[]>(stream);
88+
var firstnames = results
89+
.OrderBy(x => x.FirstName)
90+
.Select(x => x.FirstName).ToArray();
91+
92+
firstnames.Length.ShouldBe(3);
93+
firstnames[0].ShouldBe("Jeremy");
94+
firstnames[1].ShouldBe("Lindsey");
95+
firstnames[2].ShouldBe("Max");
96+
}
97+
7398
[Fact]
7499
public async Task query_by_one_parameter()
75100
{
@@ -90,6 +115,50 @@ public async Task query_by_one_parameter()
90115
firstnames[2].ShouldBe("Max");
91116
}
92117

118+
[Fact]
119+
public async Task query_by_one_parameter_async()
120+
{
121+
await using var session = theStore.LightweightSession();
122+
session.Store(new User { FirstName = "Jeremy", LastName = "Miller" });
123+
session.Store(new User { FirstName = "Lindsey", LastName = "Miller" });
124+
session.Store(new User { FirstName = "Max", LastName = "Miller" });
125+
session.Store(new User { FirstName = "Frank", LastName = "Zombo" });
126+
await session.SaveChangesAsync();
127+
128+
var firstnames =
129+
(await session.QueryAsync<User>("where data ->> 'LastName' = ?", "Miller"))
130+
.OrderBy(x => x.FirstName)
131+
.Select(x => x.FirstName)
132+
.ToArray();
133+
134+
firstnames.Length.ShouldBe(3);
135+
firstnames[0].ShouldBe("Jeremy");
136+
firstnames[1].ShouldBe("Lindsey");
137+
firstnames[2].ShouldBe("Max");
138+
}
139+
140+
[Fact]
141+
public async Task query_by_one_parameter_async_custom_placeholder()
142+
{
143+
await using var session = theStore.LightweightSession();
144+
session.Store(new User { FirstName = "Jeremy", LastName = "Miller" });
145+
session.Store(new User { FirstName = "Lindsey", LastName = "Miller" });
146+
session.Store(new User { FirstName = "Max", LastName = "Miller" });
147+
session.Store(new User { FirstName = "Frank", LastName = "Zombo" });
148+
await session.SaveChangesAsync();
149+
150+
var firstnames =
151+
(await session.QueryAsync<User>('$', "where data ->> 'LastName' = $", "Miller"))
152+
.OrderBy(x => x.FirstName)
153+
.Select(x => x.FirstName)
154+
.ToArray();
155+
156+
firstnames.Length.ShouldBe(3);
157+
firstnames[0].ShouldBe("Jeremy");
158+
firstnames[1].ShouldBe("Lindsey");
159+
firstnames[2].ShouldBe("Max");
160+
}
161+
93162
[Fact]
94163
public async Task query_ignores_case_of_where_keyword()
95164
{
@@ -280,6 +349,19 @@ public async Task query_with_matches_sql()
280349
}
281350

282351
#endregion
352+
353+
[Fact]
354+
public async Task query_with_matches_sql_custom_placeholder()
355+
{
356+
await using var session = theStore.LightweightSession();
357+
var u = new User { FirstName = "Eric", LastName = "Smith" };
358+
session.Store(u);
359+
await session.SaveChangesAsync();
360+
361+
var user = await session.Query<User>().Where(x => x.MatchesSql('$', "data->> 'FirstName' = $", "Eric")).SingleAsync();
362+
user.LastName.ShouldBe("Smith");
363+
user.Id.ShouldBe(u.Id);
364+
}
283365

284366
[Fact]
285367
public async Task query_with_select_in_query()

src/Marten/Linq/MatchesSql/MatchesSqlParser.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class MatchesSqlParser: IMethodCallParser
2626

2727
public bool Matches(MethodCallExpression expression)
2828
{
29-
return Equals(expression.Method, _sqlMethod) || Equals(expression.Method, _fragmentMethod);
29+
return Equals(expression.Method, _sqlMethod) || Equals(expression.Method, _sqlMethodWithPlaceholder) || Equals(expression.Method, _fragmentMethod);
3030
}
3131

3232
public ISqlFragment? Parse(IQueryableMemberCollection memberCollection, IReadOnlyStoreOptions options,
@@ -40,8 +40,8 @@ public bool Matches(MethodCallExpression expression)
4040

4141
if (expression.Method.Equals(_sqlMethodWithPlaceholder))
4242
{
43-
return new CustomizableWhereFragment(expression.Arguments[1].Value().As<string>(),
44-
expression.Arguments[2].Value().As<char>().ToString(),
43+
return new CustomizableWhereFragment(expression.Arguments[2].Value().As<string>(),
44+
expression.Arguments[1].Value().As<char>().ToString(),
4545
expression.Arguments[3].Value().As<object[]>());
4646
}
4747

0 commit comments

Comments
 (0)