Skip to content

Commit f9f6d2d

Browse files
authored
[release] 140 support sqlc.narg macro (#219)
1 parent 985d289 commit f9f6d2d

File tree

35 files changed

+1236
-291
lines changed

35 files changed

+1236
-291
lines changed

Drivers/DbDriver.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public abstract class DbDriver
1515

1616
public Dictionary<string, Table> Tables { get; }
1717

18-
private HashSet<string> NullableTypesInDotnetCore { get; } = ["string"];
18+
private HashSet<string> NullableTypesInDotnetCore { get; } = ["string", "object"];
1919

2020
private HashSet<string> NullableTypes { get; } = ["long", "double", "int", "float", "bool", "DateTime"];
2121

Drivers/Generators/CommonGen.cs

+6-22
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,17 @@ public string AddParametersToCommand(IEnumerable<Parameter> parameters)
2626
{{commandVar}}.Parameters.AddWithValue($"@{{param}}Arg{i}", {{argsVar}}.{{param}}[i]);
2727
""";
2828

29-
var addParamToCommand = $"""{commandVar}.Parameters.AddWithValue("@{p.Column.Name}", {argsVar}.{param});""";
30-
return ShouldCheckParameterForNull(p)
31-
? $"""
32-
if ({argsVar}.{param} != null)
33-
{addParamToCommand}
34-
"""
35-
: addParamToCommand;
29+
var nullParamCast = p.Column.NotNull ? string.Empty : " ?? (object)DBNull.Value";
30+
var addParamToCommand = $"""{commandVar}.Parameters.AddWithValue("@{p.Column.Name}", {argsVar}.{param}{nullParamCast});""";
31+
return addParamToCommand;
3632
}).JoinByNewLine();
3733
}
3834

3935
public string ConstructDapperParamsDict(IList<Parameter> parameters)
4036
{
4137
if (!parameters.Any()) return string.Empty;
42-
var initParamsDict = $"var {Variable.QueryParams.AsVarName()} = new Dictionary<string, object>();";
38+
var objectType = dbDriver.AddNullableSuffixIfNeeded("object", false);
39+
var initParamsDict = $"var {Variable.QueryParams.AsVarName()} = new Dictionary<string, {objectType}>();";
4340
var argsVar = Variable.Args.AsVarName();
4441
var queryParamsVar = Variable.QueryParams.AsVarName();
4542

@@ -53,12 +50,7 @@ public string ConstructDapperParamsDict(IList<Parameter> parameters)
5350
""";
5451

5552
var addParamToDict = $"{queryParamsVar}.Add(\"{p.Column.Name}\", {argsVar}.{param});";
56-
return ShouldCheckParameterForNull(p)
57-
? $"""
58-
if ({argsVar}.{param} != null)
59-
{addParamToDict}
60-
"""
61-
: addParamToDict;
53+
return addParamToDict;
6254
});
6355

6456
return $"""
@@ -67,14 +59,6 @@ public string ConstructDapperParamsDict(IList<Parameter> parameters)
6759
""";
6860
}
6961

70-
private bool ShouldCheckParameterForNull(Parameter parameter)
71-
{
72-
if (parameter.Column.IsArray || parameter.Column.NotNull)
73-
return false;
74-
var csharpType = dbDriver.GetCsharpType(parameter.Column);
75-
return dbDriver.IsTypeNullable(csharpType);
76-
}
77-
7862
public static string AwaitReaderRow()
7963
{
8064
return $"await {Variable.Reader.AsVarName()}.ReadAsync()";

Drivers/SqliteDriver.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ public override string CreateSqlCommand(string sqlTextConstant)
5757
public override string TransformQueryText(Query query)
5858
{
5959
var counter = 0;
60-
return QueryParamRegex().Replace(query.Text, _ => "@" + query.Params[counter++].Column.Name);
60+
var transformedQueryText = QueryParamRegex().Replace(query.Text, _ => "@" + query.Params[counter++].Column.Name);
61+
62+
return transformedQueryText;
6163
}
6264

63-
[GeneratedRegex(@"\?")]
65+
[GeneratedRegex(@"\?\d*")]
6466
private static partial Regex QueryParamRegex();
6567

6668
public MemberDeclarationSyntax OneDeclare(string queryTextConstant, string argInterface,

docs/03_Usage.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ More info can be found in [here](https://docs.sqlc.dev/en/stable/reference/query
4646
| Annotation | PostgresSQL | MySQL | SQLite |
4747
|-------------|-------------|-------|---------|
4848
| sqlc.arg ||||
49-
| sqlc.narg | | | |
49+
| sqlc.narg | | | |
5050
| sqlc.slice | 🚫 |||
5151
| sqlc.embed ||||
5252

end2end/EndToEndScaffold/Config.cs

+20-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public enum KnownTestType
2525
PartialEmbed,
2626
Slice,
2727
MultipleSlices,
28+
NargNull,
29+
NargNotNull,
2830

2931
// data types aligned tests
3032
ArrayAsParam,
@@ -56,7 +58,9 @@ internal static class Config
5658
KnownTestType.Slice,
5759
KnownTestType.MultipleSlices,
5860
KnownTestType.MySqlCopyFrom,
59-
KnownTestType.MySqlDataTypes
61+
KnownTestType.MySqlDataTypes,
62+
KnownTestType.NargNull,
63+
KnownTestType.NargNotNull
6064
]
6165
}
6266
},
@@ -76,7 +80,9 @@ internal static class Config
7680
KnownTestType.Slice,
7781
KnownTestType.MultipleSlices,
7882
KnownTestType.MySqlCopyFrom,
79-
KnownTestType.MySqlDataTypes
83+
KnownTestType.MySqlDataTypes,
84+
KnownTestType.NargNull,
85+
KnownTestType.NargNotNull
8086
]
8187
}
8288
},
@@ -96,7 +102,9 @@ internal static class Config
96102
KnownTestType.ArrayAsParam,
97103
KnownTestType.MultipleArraysAsParams,
98104
KnownTestType.PostgresCopyFrom,
99-
KnownTestType.PostgresDataTypes
105+
KnownTestType.PostgresDataTypes,
106+
KnownTestType.NargNull,
107+
KnownTestType.NargNotNull
100108
]
101109
}
102110
},
@@ -116,7 +124,9 @@ internal static class Config
116124
KnownTestType.ArrayAsParam,
117125
KnownTestType.MultipleArraysAsParams,
118126
KnownTestType.PostgresCopyFrom,
119-
KnownTestType.PostgresDataTypes
127+
KnownTestType.PostgresDataTypes,
128+
KnownTestType.NargNull,
129+
KnownTestType.NargNotNull
120130
]
121131
}
122132
},
@@ -135,7 +145,9 @@ internal static class Config
135145
KnownTestType.SelfJoinEmbed,
136146
KnownTestType.Slice,
137147
KnownTestType.MultipleSlices,
138-
KnownTestType.SqliteDataTypes
148+
KnownTestType.SqliteDataTypes,
149+
KnownTestType.NargNull,
150+
KnownTestType.NargNotNull
139151
]
140152
}
141153
},
@@ -154,7 +166,9 @@ internal static class Config
154166
KnownTestType.SelfJoinEmbed,
155167
KnownTestType.Slice,
156168
KnownTestType.MultipleSlices,
157-
KnownTestType.SqliteDataTypes
169+
KnownTestType.SqliteDataTypes,
170+
KnownTestType.NargNull,
171+
KnownTestType.NargNotNull,
158172
]
159173
}
160174
},

end2end/EndToEndScaffold/Templates.cs

+66
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,72 @@ private static bool SingularEquals(QuerySql.GetSqliteTypesRow x, QuerySql.GetSql
729729
// TODO add CBlob.Equals - fix impl
730730
}
731731
"""
732+
},
733+
[KnownTestType.NargNull] = new TestImpl
734+
{
735+
Impl = $$"""
736+
[Test]
737+
public async Task TestNargNull()
738+
{
739+
{{CreateBojackAuthor}}
740+
{{CreateDrSeussAuthor}}
741+
var expected = new List<QuerySql.GetAuthorByNamePatternRow>
742+
{
743+
new QuerySql.GetAuthorByNamePatternRow
744+
{
745+
Id = {{BojackId}},
746+
Name = {{BojackAuthor}},
747+
Bio = {{BojackTheme}}
748+
},
749+
new QuerySql.GetAuthorByNamePatternRow
750+
{
751+
Id = {{DrSeussId}},
752+
Name = {{DrSeussAuthor}},
753+
Bio = {{DrSeussQuote}}
754+
}
755+
};
756+
757+
var actual = await this.QuerySql.GetAuthorByNamePattern(new QuerySql.GetAuthorByNamePatternArgs());
758+
Assert.That(SequenceEquals(expected, actual));
759+
}
760+
761+
private static bool SequenceEquals(List<QuerySql.GetAuthorByNamePatternRow> x, List<QuerySql.GetAuthorByNamePatternRow> y)
762+
{
763+
if (x.Count != y.Count)
764+
return false;
765+
x = x.OrderBy<QuerySql.GetAuthorByNamePatternRow, object>(o => o.Id).ToList();
766+
y = y.OrderBy<QuerySql.GetAuthorByNamePatternRow, object>(o => o.Id).ToList();
767+
return !x.Where((t, i) => !SingularEquals(t, y[i])).Any();
768+
}
769+
private static bool SingularEquals(QuerySql.GetAuthorByNamePatternRow x, QuerySql.GetAuthorByNamePatternRow y)
770+
{
771+
return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio);
772+
}
773+
"""
774+
},
775+
[KnownTestType.NargNotNull] = new TestImpl
776+
{
777+
Impl = $$"""
778+
[Test]
779+
public async Task TestNargNotNull()
780+
{
781+
{{CreateBojackAuthor}}
782+
{{CreateDrSeussAuthor}}
783+
784+
var expected = new List<QuerySql.GetAuthorByNamePatternRow>
785+
{
786+
new QuerySql.GetAuthorByNamePatternRow
787+
{
788+
Id = {{BojackId}},
789+
Name = {{BojackAuthor}},
790+
Bio = {{BojackTheme}}
791+
}
792+
};
793+
794+
var actual = await this.QuerySql.GetAuthorByNamePattern(new QuerySql.GetAuthorByNamePatternArgs { NamePattern = "Bojack%" });
795+
Assert.That(SequenceEquals(expected, actual));
796+
}
797+
"""
732798
}
733799
};
734800
}

end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs

+56
Original file line numberDiff line numberDiff line change
@@ -295,5 +295,61 @@ private static bool SingularEquals(QuerySql.GetMysqlTypesRow x, QuerySql.GetMysq
295295
{
296296
return x.CBit.Equals(y.CBit) && x.CTinyint.Equals(y.CTinyint) && x.CBool.Equals(y.CBool) && x.CBoolean.Equals(y.CBoolean) && x.CInt.Equals(y.CInt) && x.CVarchar.Equals(y.CVarchar) && x.CDate.Equals(y.CDate) && x.CTimestamp.Equals(y.CTimestamp);
297297
}
298+
299+
[Test]
300+
public async Task TestNargNull()
301+
{
302+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" });
303+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 2222, Name = "Dr. Seuss", Bio = "You'll miss the best things if you keep your eyes shut" });
304+
var expected = new List<QuerySql.GetAuthorByNamePatternRow>
305+
{
306+
new QuerySql.GetAuthorByNamePatternRow
307+
{
308+
Id = 1111,
309+
Name = "Bojack Horseman",
310+
Bio = "Back in the 90s he was in a very famous TV show"
311+
},
312+
new QuerySql.GetAuthorByNamePatternRow
313+
{
314+
Id = 2222,
315+
Name = "Dr. Seuss",
316+
Bio = "You'll miss the best things if you keep your eyes shut"
317+
}
318+
};
319+
var actual = await this.QuerySql.GetAuthorByNamePattern(new QuerySql.GetAuthorByNamePatternArgs());
320+
Assert.That(SequenceEquals(expected, actual));
321+
}
322+
323+
private static bool SequenceEquals(List<QuerySql.GetAuthorByNamePatternRow> x, List<QuerySql.GetAuthorByNamePatternRow> y)
324+
{
325+
if (x.Count != y.Count)
326+
return false;
327+
x = x.OrderBy<QuerySql.GetAuthorByNamePatternRow, object>(o => o.Id).ToList();
328+
y = y.OrderBy<QuerySql.GetAuthorByNamePatternRow, object>(o => o.Id).ToList();
329+
return !x.Where((t, i) => !SingularEquals(t, y[i])).Any();
330+
}
331+
332+
private static bool SingularEquals(QuerySql.GetAuthorByNamePatternRow x, QuerySql.GetAuthorByNamePatternRow y)
333+
{
334+
return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio);
335+
}
336+
337+
[Test]
338+
public async Task TestNargNotNull()
339+
{
340+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" });
341+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 2222, Name = "Dr. Seuss", Bio = "You'll miss the best things if you keep your eyes shut" });
342+
var expected = new List<QuerySql.GetAuthorByNamePatternRow>
343+
{
344+
new QuerySql.GetAuthorByNamePatternRow
345+
{
346+
Id = 1111,
347+
Name = "Bojack Horseman",
348+
Bio = "Back in the 90s he was in a very famous TV show"
349+
}
350+
};
351+
var actual = await this.QuerySql.GetAuthorByNamePattern(new QuerySql.GetAuthorByNamePatternArgs { NamePattern = "Bojack%" });
352+
Assert.That(SequenceEquals(expected, actual));
353+
}
298354
}
299355
}

end2end/EndToEndTests/MySqlConnectorTester.cs

-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
using MySqlConnectorExampleGen;
22
using NUnit.Framework;
3-
using NUnit.Framework.Legacy;
43
using System;
5-
using System.Linq;
64
using System.Threading.Tasks;
75

86
namespace SqlcGenCsharpTests;
97

10-
[TestFixture]
118
public partial class MySqlConnectorTester
129
{
1310
private QuerySql QuerySql { get; } = new(

end2end/EndToEndTests/MySqlConnectorTester.generated.cs

+56
Original file line numberDiff line numberDiff line change
@@ -295,5 +295,61 @@ private static bool SingularEquals(QuerySql.GetMysqlTypesRow x, QuerySql.GetMysq
295295
{
296296
return x.CBit.Equals(y.CBit) && x.CTinyint.Equals(y.CTinyint) && x.CBool.Equals(y.CBool) && x.CBoolean.Equals(y.CBoolean) && x.CInt.Equals(y.CInt) && x.CVarchar.Equals(y.CVarchar) && x.CDate.Equals(y.CDate) && x.CTimestamp.Equals(y.CTimestamp);
297297
}
298+
299+
[Test]
300+
public async Task TestNargNull()
301+
{
302+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" });
303+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 2222, Name = "Dr. Seuss", Bio = "You'll miss the best things if you keep your eyes shut" });
304+
var expected = new List<QuerySql.GetAuthorByNamePatternRow>
305+
{
306+
new QuerySql.GetAuthorByNamePatternRow
307+
{
308+
Id = 1111,
309+
Name = "Bojack Horseman",
310+
Bio = "Back in the 90s he was in a very famous TV show"
311+
},
312+
new QuerySql.GetAuthorByNamePatternRow
313+
{
314+
Id = 2222,
315+
Name = "Dr. Seuss",
316+
Bio = "You'll miss the best things if you keep your eyes shut"
317+
}
318+
};
319+
var actual = await this.QuerySql.GetAuthorByNamePattern(new QuerySql.GetAuthorByNamePatternArgs());
320+
Assert.That(SequenceEquals(expected, actual));
321+
}
322+
323+
private static bool SequenceEquals(List<QuerySql.GetAuthorByNamePatternRow> x, List<QuerySql.GetAuthorByNamePatternRow> y)
324+
{
325+
if (x.Count != y.Count)
326+
return false;
327+
x = x.OrderBy<QuerySql.GetAuthorByNamePatternRow, object>(o => o.Id).ToList();
328+
y = y.OrderBy<QuerySql.GetAuthorByNamePatternRow, object>(o => o.Id).ToList();
329+
return !x.Where((t, i) => !SingularEquals(t, y[i])).Any();
330+
}
331+
332+
private static bool SingularEquals(QuerySql.GetAuthorByNamePatternRow x, QuerySql.GetAuthorByNamePatternRow y)
333+
{
334+
return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio);
335+
}
336+
337+
[Test]
338+
public async Task TestNargNotNull()
339+
{
340+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" });
341+
await this.QuerySql.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 2222, Name = "Dr. Seuss", Bio = "You'll miss the best things if you keep your eyes shut" });
342+
var expected = new List<QuerySql.GetAuthorByNamePatternRow>
343+
{
344+
new QuerySql.GetAuthorByNamePatternRow
345+
{
346+
Id = 1111,
347+
Name = "Bojack Horseman",
348+
Bio = "Back in the 90s he was in a very famous TV show"
349+
}
350+
};
351+
var actual = await this.QuerySql.GetAuthorByNamePattern(new QuerySql.GetAuthorByNamePatternArgs { NamePattern = "Bojack%" });
352+
Assert.That(SequenceEquals(expected, actual));
353+
}
298354
}
299355
}

0 commit comments

Comments
 (0)