diff --git a/Drivers/MySqlConnectorDriver.cs b/Drivers/MySqlConnectorDriver.cs index c90e1f7f..b02177a2 100644 --- a/Drivers/MySqlConnectorDriver.cs +++ b/Drivers/MySqlConnectorDriver.cs @@ -96,6 +96,7 @@ public partial class MySqlConnectorDriver( new() { { "int", new() }, + { "integer", new() }, { "mediumint", new() } }, ordinal => $"reader.GetInt32({ordinal})", @@ -282,9 +283,14 @@ public override string TransformQueryText(Query query) if (query.Cmd == ":copyfrom") return string.Empty; - var queryText = Options.UseDapper ? $"{query.Text}; SELECT LAST_INSERT_ID()" : query.Text; var counter = 0; - return QueryParamRegex().Replace(queryText, _ => "@" + query.Params[counter++].Column.Name); + var queryText = query.Text; + queryText = QueryParamRegex().Replace(queryText, _ => "@" + query.Params[counter++].Column.Name); + queryText = Options.UseDapper && query.Cmd == ":execlastid" + ? $"{queryText}; SELECT LAST_INSERT_ID()" + : queryText; + + return queryText; } [GeneratedRegex(@"\?")] diff --git a/Drivers/SqliteDriver.cs b/Drivers/SqliteDriver.cs index 61d517a7..2796d406 100644 --- a/Drivers/SqliteDriver.cs +++ b/Drivers/SqliteDriver.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Plugin; using SqlcGenCsharp.Drivers.Generators; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -12,7 +13,7 @@ public partial class SqliteDriver( Options options, string defaultSchema, Dictionary> tables, - Dictionary> enums, + Dictionary> enums, IList queries) : DbDriver(options, defaultSchema, tables, enums, queries), IOne, IMany, IExec, IExecRows, IExecLastId, ICopyFrom { @@ -130,13 +131,18 @@ public override string CreateSqlCommand(string sqlTextConstant) public override string TransformQueryText(Query query) { - var counter = 0; - var transformedQueryText = QueryParamRegex().Replace(query.Text, _ => "@" + query.Params[counter++].Column.Name); - return transformedQueryText; - } + var areArgumentsNumbered = new Regex($@"\?\d\b*").IsMatch(query.Text); + var queryText = query.Text; - [GeneratedRegex(@"\?\d*")] - private static partial Regex QueryParamRegex(); + for (var i = 0; i < query.Params.Count; i++) + { + var currentParameter = query.Params[i]; + var column = GetColumnFromParam(currentParameter, query); + var regexToUse = areArgumentsNumbered ? $@"\?{i + 1}\b*" : $@"\?\b*"; + queryText = new Regex(regexToUse).Replace(queryText, $"@{column.Name}", 1); + } + return queryText; + } public MemberDeclarationSyntax OneDeclare(string queryTextConstant, string argInterface, string returnInterface, Query query) diff --git a/end2end/EndToEndScaffold/Templates/AnnotationTests.cs b/end2end/EndToEndScaffold/Templates/AnnotationTests.cs index ff55f8a6..4bebe4e8 100644 --- a/end2end/EndToEndScaffold/Templates/AnnotationTests.cs +++ b/end2end/EndToEndScaffold/Templates/AnnotationTests.cs @@ -60,23 +60,28 @@ public async Task TestMany() Bio = {{Consts.DrSeussQuote}} } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs + { + Limit = 2, + Offset = 0 + }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && - x.Name.Equals(y.Name) && - x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } """ }, @@ -128,8 +133,12 @@ public async Task TestExecRows() Bio = {{Consts.GenericQuote1}} } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs + { + Limit = 2, + Offset = 0 + }); + AssertSequenceEquals(expected, actual); } """, }, diff --git a/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs b/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs index 405e2a3d..41ed65a2 100644 --- a/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs +++ b/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs @@ -52,22 +52,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -102,8 +104,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTests/MySqlConnectorTester.generated.cs b/end2end/EndToEndTests/MySqlConnectorTester.generated.cs index c3f8d2c1..039ec10d 100644 --- a/end2end/EndToEndTests/MySqlConnectorTester.generated.cs +++ b/end2end/EndToEndTests/MySqlConnectorTester.generated.cs @@ -52,22 +52,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -102,8 +104,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs b/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs index 0cb78dbd..10e8eeef 100644 --- a/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs +++ b/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs @@ -55,22 +55,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -105,8 +107,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTests/NpgsqlTester.generated.cs b/end2end/EndToEndTests/NpgsqlTester.generated.cs index 305bcd71..e4cae233 100644 --- a/end2end/EndToEndTests/NpgsqlTester.generated.cs +++ b/end2end/EndToEndTests/NpgsqlTester.generated.cs @@ -55,22 +55,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -105,8 +107,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTests/SqliteDapperTester.generated.cs b/end2end/EndToEndTests/SqliteDapperTester.generated.cs index 64a4dee5..75cb0272 100644 --- a/end2end/EndToEndTests/SqliteDapperTester.generated.cs +++ b/end2end/EndToEndTests/SqliteDapperTester.generated.cs @@ -51,22 +51,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -101,8 +103,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTests/SqliteTester.generated.cs b/end2end/EndToEndTests/SqliteTester.generated.cs index e4c7aad5..d2070c6f 100644 --- a/end2end/EndToEndTests/SqliteTester.generated.cs +++ b/end2end/EndToEndTests/SqliteTester.generated.cs @@ -51,22 +51,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -101,8 +103,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs b/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs index 2a4252f0..96096318 100644 --- a/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs @@ -52,22 +52,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -102,8 +104,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs b/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs index 18ab2487..90cf6073 100644 --- a/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs @@ -52,22 +52,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -102,8 +104,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs b/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs index 2e90878c..9ecb0435 100644 --- a/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs @@ -55,22 +55,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -105,8 +107,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs b/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs index e4323c50..2060aa5c 100644 --- a/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs @@ -55,22 +55,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -105,8 +107,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs b/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs index 64ef7e14..4224f7e1 100644 --- a/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs @@ -51,22 +51,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -101,8 +103,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs b/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs index 5ca0cf9f..39ea0f7f 100644 --- a/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs @@ -51,22 +51,24 @@ public async Task TestMany() Bio = "You'll miss the best things if you keep your eyes shut" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } - private static bool SingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) + private static void AssertSingularEquals(QuerySql.ListAuthorsRow x, QuerySql.ListAuthorsRow y) { - return x.Id.Equals(y.Id) && x.Name.Equals(y.Name) && x.Bio.Equals(y.Bio); + Assert.That(x.Id, Is.EqualTo(y.Id)); + Assert.That(x.Name, Is.EqualTo(y.Name)); + Assert.That(x.Bio, Is.EqualTo(y.Bio)); } - private static bool SequenceEquals(List x, List y) + private static void AssertSequenceEquals(List x, List y) { - if (x.Count != y.Count) - return false; - x = x.OrderBy(o => o.Id).ToList(); - y = y.OrderBy(o => o.Id).ToList(); - return !x.Where((t, i) => !SingularEquals(t, y[i])).Any(); + Assert.That(x.Count, Is.EqualTo(y.Count)); + for (int i = 0; i < x.Count; i++) + { + AssertSingularEquals(x[i], y[i]); + } } [Test] @@ -101,8 +103,8 @@ public async Task TestExecRows() Bio = "Quote that everyone always attribute to Einstein" } }; - var actual = await this.QuerySql.ListAuthors(); - Assert.That(SequenceEquals(expected, actual)); + var actual = await this.QuerySql.ListAuthors(new QuerySql.ListAuthorsArgs { Limit = 2, Offset = 0 }); + AssertSequenceEquals(expected, actual); } [Test] diff --git a/examples/MySqlConnectorDapperExample/QuerySql.cs b/examples/MySqlConnectorDapperExample/QuerySql.cs index a005180e..e8dd0a40 100644 --- a/examples/MySqlConnectorDapperExample/QuerySql.cs +++ b/examples/MySqlConnectorDapperExample/QuerySql.cs @@ -44,7 +44,7 @@ public static QuerySql WithTransaction(MySqlTransaction transaction) private MySqlTransaction? Transaction { get; } private string? ConnectionString { get; } - private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1"; public class GetAuthorRow { public required long Id { get; init; } @@ -76,30 +76,38 @@ public class GetAuthorArgs return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name ; SELECT LAST_INSERT_ID ( ) "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public required long Id { get; init; } public required string Name { get; init; } public string? Bio { get; init; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs { + public required int Limit { get; init; } + public required int Offset { get; init; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) + { + var queryParams = new Dictionary(); + queryParams.Add("limit", args.Limit); + queryParams.Add("offset", args.Offset); if (this.Transaction == null) { using (var connection = new MySqlConnection(ConnectionString)) { - var result = await connection.QueryAsync(ListAuthorsSql); + var result = await connection.QueryAsync(ListAuthorsSql, queryParams); return result.AsList(); } } if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) throw new InvalidOperationException("Transaction is provided, but its connection is null."); - return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, queryParams, transaction: this.Transaction)).AsList(); } - private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio); SELECT LAST_INSERT_ID()"; + private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio)"; public class CreateAuthorArgs { public required long Id { get; init; } @@ -157,7 +165,7 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } - private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1"; public class GetAuthorByIdRow { public required long Id { get; init; } @@ -189,7 +197,7 @@ public class GetAuthorByIdArgs return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } - private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) ; SELECT LAST_INSERT_ID ( ) "; + private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) "; public class GetAuthorByNamePatternRow { public required long Id { get; init; } @@ -218,7 +226,7 @@ public async Task> GetAuthorByNamePattern(GetAut return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } - private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name ; SELECT LAST_INSERT_ID ( ) "; + private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name "; public class DeleteAuthorArgs { public required string Name { get; init; } @@ -245,7 +253,7 @@ public async Task DeleteAuthor(DeleteAuthorArgs args) await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } - private const string DeleteAllAuthorsSql = "DELETE FROM authors; SELECT LAST_INSERT_ID()"; + private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { if (this.Transaction == null) @@ -266,7 +274,7 @@ public async Task DeleteAllAuthors() await this.Transaction.Connection.ExecuteAsync(DeleteAllAuthorsSql, transaction: this.Transaction); } - private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL ; SELECT LAST_INSERT_ID ( ) "; + private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL "; public class UpdateAuthorsArgs { public string? Bio { get; init; } @@ -291,7 +299,7 @@ public async Task UpdateAuthors(UpdateAuthorsArgs args) return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } - private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids); SELECT LAST_INSERT_ID()"; + private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; public class GetAuthorsByIdsRow { public required long Id { get; init; } @@ -323,7 +331,7 @@ public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } - private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names); SELECT LAST_INSERT_ID()"; + private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names)"; public class GetAuthorsByIdsAndNamesRow { public required long Id { get; init; } @@ -386,7 +394,7 @@ public async Task CreateBook(CreateBookArgs args) return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } - private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name ; SELECT LAST_INSERT_ID ( ) "; + private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name "; public class ListAllAuthorsBooksRow { public required Author? Author { get; init; } @@ -428,7 +436,7 @@ public async Task> ListAllAuthorsBooks() } } - private const string GetDuplicateAuthorsSql = "SELECT authors1.id, authors1.name, authors1.bio, authors2.id, authors2.name, authors2.bio FROM authors authors1 JOIN authors authors2 ON authors1 . name = authors2 . name WHERE authors1 . id < authors2 . id ; SELECT LAST_INSERT_ID ( ) "; + private const string GetDuplicateAuthorsSql = "SELECT authors1.id, authors1.name, authors1.bio, authors2.id, authors2.name, authors2.bio FROM authors authors1 JOIN authors authors2 ON authors1 . name = authors2 . name WHERE authors1 . id < authors2 . id "; public class GetDuplicateAuthorsRow { public required Author? Author { get; init; } @@ -470,7 +478,7 @@ public async Task> GetDuplicateAuthors() } } - private const string GetAuthorsByBookNameSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id WHERE books . name = @name ; SELECT LAST_INSERT_ID ( ) "; + private const string GetAuthorsByBookNameSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id WHERE books . name = @name "; public class GetAuthorsByBookNameRow { public required long Id { get; init; } @@ -520,7 +528,7 @@ public async Task> GetAuthorsByBookName(GetAuthors } } - private const string InsertMysqlTypesSql = "INSERT INTO mysql_types (c_bit, c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_decimal, c_dec, c_numeric, c_fixed, c_float, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob) VALUES ( @c_bit, @c_bool, @c_boolean, @c_tinyint, @c_smallint, @c_mediumint, @c_int, @c_integer, @c_bigint, @c_decimal, @c_dec, @c_numeric, @c_fixed, @c_float, @c_double, @c_double_precision, @c_char, @c_nchar, @c_national_char, @c_varchar, @c_tinytext, @c_mediumtext, @c_text, @c_longtext, @c_enum, @c_json, @c_json_string_override, @c_year, @c_date, @c_datetime, @c_timestamp, @c_binary, @c_varbinary, @c_tinyblob, @c_blob, @c_mediumblob, @c_longblob ); SELECT LAST_INSERT_ID ( ) "; + private const string InsertMysqlTypesSql = "INSERT INTO mysql_types (c_bit, c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_decimal, c_dec, c_numeric, c_fixed, c_float, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob) VALUES ( @c_bit, @c_bool, @c_boolean, @c_tinyint, @c_smallint, @c_mediumint, @c_int, @c_integer, @c_bigint, @c_decimal, @c_dec, @c_numeric, @c_fixed, @c_float, @c_double, @c_double_precision, @c_char, @c_nchar, @c_national_char, @c_varchar, @c_tinytext, @c_mediumtext, @c_text, @c_longtext, @c_enum, @c_json, @c_json_string_override, @c_year, @c_date, @c_datetime, @c_timestamp, @c_binary, @c_varbinary, @c_tinyblob, @c_blob, @c_mediumblob, @c_longblob ) "; public class InsertMysqlTypesArgs { public byte? CBit { get; init; } @@ -718,7 +726,7 @@ public async Task InsertMysqlTypesBatch(List args) } } - private const string GetMysqlTypesSql = "SELECT c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_decimal, c_dec, c_numeric, c_fixed, c_double, c_double_precision, c_year, c_date, c_time, c_datetime, c_timestamp, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_bit, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetMysqlTypesSql = "SELECT c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_decimal, c_dec, c_numeric, c_fixed, c_double, c_double_precision, c_year, c_date, c_time, c_datetime, c_timestamp, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_bit, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types LIMIT 1"; public class GetMysqlTypesRow { public bool? CBool { get; init; } @@ -779,7 +787,7 @@ public class GetMysqlTypesRow return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql, transaction: this.Transaction); } - private const string GetMysqlTypesCntSql = "SELECT COUNT(1) AS cnt, c_bool, c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float , c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types GROUP BY c_bool , c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob LIMIT 1 ; SELECT LAST_INSERT_ID ( ) "; + private const string GetMysqlTypesCntSql = "SELECT COUNT(1) AS cnt, c_bool, c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float , c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types GROUP BY c_bool , c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob LIMIT 1 "; public class GetMysqlTypesCntRow { public required long Cnt { get; init; } @@ -840,7 +848,7 @@ public class GetMysqlTypesCntRow return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql, transaction: this.Transaction); } - private const string GetMysqlFunctionsSql = "SELECT MAX(c_int) AS max_int, MAX(c_varchar) AS max_varchar, MAX(c_timestamp) AS max_timestamp FROM mysql_types ; SELECT LAST_INSERT_ID ( ) "; + private const string GetMysqlFunctionsSql = "SELECT MAX(c_int) AS max_int, MAX(c_varchar) AS max_varchar, MAX(c_timestamp) AS max_timestamp FROM mysql_types "; public class GetMysqlFunctionsRow { public int? MaxInt { get; init; } @@ -866,7 +874,7 @@ public class GetMysqlFunctionsRow return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql, transaction: this.Transaction); } - private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types; SELECT LAST_INSERT_ID()"; + private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types"; public async Task TruncateMysqlTypes() { if (this.Transaction == null) @@ -887,7 +895,7 @@ public async Task TruncateMysqlTypes() await this.Transaction.Connection.ExecuteAsync(TruncateMysqlTypesSql, transaction: this.Transaction); } - private const string CreateExtendedBioSql = "INSERT INTO extended.bios (author_name, name, bio_type) VALUES (@author_name, @name, @bio_type); SELECT LAST_INSERT_ID()"; + private const string CreateExtendedBioSql = "INSERT INTO extended.bios (author_name, name, bio_type) VALUES (@author_name, @name, @bio_type)"; public class CreateExtendedBioArgs { public string? AuthorName { get; init; } @@ -918,7 +926,7 @@ public async Task CreateExtendedBio(CreateExtendedBioArgs args) await this.Transaction.Connection.ExecuteAsync(CreateExtendedBioSql, queryParams, transaction: this.Transaction); } - private const string GetFirstExtendedBioByTypeSql = "SELECT author_name, name, bio_type FROM extended.bios WHERE bio_type = @bio_type LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetFirstExtendedBioByTypeSql = "SELECT author_name, name, bio_type FROM extended.bios WHERE bio_type = @bio_type LIMIT 1"; public class GetFirstExtendedBioByTypeRow { public string? AuthorName { get; init; } @@ -950,7 +958,7 @@ public class GetFirstExtendedBioByTypeArgs return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams, transaction: this.Transaction); } - private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios; SELECT LAST_INSERT_ID()"; + private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios"; public async Task TruncateExtendedBios() { if (this.Transaction == null) diff --git a/examples/MySqlConnectorDapperExample/request.json b/examples/MySqlConnectorDapperExample/request.json index 96c58ad2..ecaebaf5 100644 --- a/examples/MySqlConnectorDapperExample/request.json +++ b/examples/MySqlConnectorDapperExample/request.json @@ -629,7 +629,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT ? OFFSET ?", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -669,6 +669,30 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/MySqlConnectorDapperExample/request.message b/examples/MySqlConnectorDapperExample/request.message index f143fe7e..324a9d97 100644 Binary files a/examples/MySqlConnectorDapperExample/request.message and b/examples/MySqlConnectorDapperExample/request.message differ diff --git a/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs b/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs index 5df5222d..12a09c9a 100644 --- a/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs +++ b/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs @@ -45,7 +45,7 @@ public static QuerySql WithTransaction(MySqlTransaction transaction) private MySqlTransaction Transaction { get; } private string ConnectionString { get; } - private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1"; public class GetAuthorRow { public long Id { get; set; } @@ -77,30 +77,38 @@ public async Task GetAuthor(GetAuthorArgs args) return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name ; SELECT LAST_INSERT_ID ( ) "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public long Id { get; set; } public string Name { get; set; } public string Bio { get; set; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs { + public int Limit { get; set; } + public int Offset { get; set; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) + { + var queryParams = new Dictionary(); + queryParams.Add("limit", args.Limit); + queryParams.Add("offset", args.Offset); if (this.Transaction == null) { using (var connection = new MySqlConnection(ConnectionString)) { - var result = await connection.QueryAsync(ListAuthorsSql); + var result = await connection.QueryAsync(ListAuthorsSql, queryParams); return result.AsList(); } } if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) throw new InvalidOperationException("Transaction is provided, but its connection is null."); - return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, queryParams, transaction: this.Transaction)).AsList(); } - private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio); SELECT LAST_INSERT_ID()"; + private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio)"; public class CreateAuthorArgs { public long Id { get; set; } @@ -158,7 +166,7 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } - private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1"; public class GetAuthorByIdRow { public long Id { get; set; } @@ -190,7 +198,7 @@ public async Task GetAuthorById(GetAuthorByIdArgs args) return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } - private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) ; SELECT LAST_INSERT_ID ( ) "; + private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) "; public class GetAuthorByNamePatternRow { public long Id { get; set; } @@ -219,7 +227,7 @@ public async Task> GetAuthorByNamePattern(GetAut return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } - private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name ; SELECT LAST_INSERT_ID ( ) "; + private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name "; public class DeleteAuthorArgs { public string Name { get; set; } @@ -246,7 +254,7 @@ public async Task DeleteAuthor(DeleteAuthorArgs args) await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } - private const string DeleteAllAuthorsSql = "DELETE FROM authors; SELECT LAST_INSERT_ID()"; + private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { if (this.Transaction == null) @@ -267,7 +275,7 @@ public async Task DeleteAllAuthors() await this.Transaction.Connection.ExecuteAsync(DeleteAllAuthorsSql, transaction: this.Transaction); } - private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL ; SELECT LAST_INSERT_ID ( ) "; + private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL "; public class UpdateAuthorsArgs { public string Bio { get; set; } @@ -292,7 +300,7 @@ public async Task UpdateAuthors(UpdateAuthorsArgs args) return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } - private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids); SELECT LAST_INSERT_ID()"; + private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; public class GetAuthorsByIdsRow { public long Id { get; set; } @@ -324,7 +332,7 @@ public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } - private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names); SELECT LAST_INSERT_ID()"; + private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names)"; public class GetAuthorsByIdsAndNamesRow { public long Id { get; set; } @@ -387,7 +395,7 @@ public async Task CreateBook(CreateBookArgs args) return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } - private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name ; SELECT LAST_INSERT_ID ( ) "; + private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name "; public class ListAllAuthorsBooksRow { public Author Author { get; set; } @@ -429,7 +437,7 @@ public async Task> ListAllAuthorsBooks() } } - private const string GetDuplicateAuthorsSql = "SELECT authors1.id, authors1.name, authors1.bio, authors2.id, authors2.name, authors2.bio FROM authors authors1 JOIN authors authors2 ON authors1 . name = authors2 . name WHERE authors1 . id < authors2 . id ; SELECT LAST_INSERT_ID ( ) "; + private const string GetDuplicateAuthorsSql = "SELECT authors1.id, authors1.name, authors1.bio, authors2.id, authors2.name, authors2.bio FROM authors authors1 JOIN authors authors2 ON authors1 . name = authors2 . name WHERE authors1 . id < authors2 . id "; public class GetDuplicateAuthorsRow { public Author Author { get; set; } @@ -471,7 +479,7 @@ public async Task> GetDuplicateAuthors() } } - private const string GetAuthorsByBookNameSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id WHERE books . name = @name ; SELECT LAST_INSERT_ID ( ) "; + private const string GetAuthorsByBookNameSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id WHERE books . name = @name "; public class GetAuthorsByBookNameRow { public long Id { get; set; } @@ -521,7 +529,7 @@ public async Task> GetAuthorsByBookName(GetAuthors } } - private const string InsertMysqlTypesSql = "INSERT INTO mysql_types (c_bit, c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_decimal, c_dec, c_numeric, c_fixed, c_float, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob) VALUES ( @c_bit, @c_bool, @c_boolean, @c_tinyint, @c_smallint, @c_mediumint, @c_int, @c_integer, @c_bigint, @c_decimal, @c_dec, @c_numeric, @c_fixed, @c_float, @c_double, @c_double_precision, @c_char, @c_nchar, @c_national_char, @c_varchar, @c_tinytext, @c_mediumtext, @c_text, @c_longtext, @c_enum, @c_json, @c_json_string_override, @c_year, @c_date, @c_datetime, @c_timestamp, @c_binary, @c_varbinary, @c_tinyblob, @c_blob, @c_mediumblob, @c_longblob ); SELECT LAST_INSERT_ID ( ) "; + private const string InsertMysqlTypesSql = "INSERT INTO mysql_types (c_bit, c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_decimal, c_dec, c_numeric, c_fixed, c_float, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob) VALUES ( @c_bit, @c_bool, @c_boolean, @c_tinyint, @c_smallint, @c_mediumint, @c_int, @c_integer, @c_bigint, @c_decimal, @c_dec, @c_numeric, @c_fixed, @c_float, @c_double, @c_double_precision, @c_char, @c_nchar, @c_national_char, @c_varchar, @c_tinytext, @c_mediumtext, @c_text, @c_longtext, @c_enum, @c_json, @c_json_string_override, @c_year, @c_date, @c_datetime, @c_timestamp, @c_binary, @c_varbinary, @c_tinyblob, @c_blob, @c_mediumblob, @c_longblob ) "; public class InsertMysqlTypesArgs { public byte? CBit { get; set; } @@ -718,7 +726,7 @@ public async Task InsertMysqlTypesBatch(List args) } } - private const string GetMysqlTypesSql = "SELECT c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_decimal, c_dec, c_numeric, c_fixed, c_double, c_double_precision, c_year, c_date, c_time, c_datetime, c_timestamp, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_bit, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetMysqlTypesSql = "SELECT c_bool, c_boolean, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_decimal, c_dec, c_numeric, c_fixed, c_double, c_double_precision, c_year, c_date, c_time, c_datetime, c_timestamp, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_bit, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types LIMIT 1"; public class GetMysqlTypesRow { public bool? CBool { get; set; } @@ -779,7 +787,7 @@ public async Task GetMysqlTypes() return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql, transaction: this.Transaction); } - private const string GetMysqlTypesCntSql = "SELECT COUNT(1) AS cnt, c_bool, c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float , c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types GROUP BY c_bool , c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob LIMIT 1 ; SELECT LAST_INSERT_ID ( ) "; + private const string GetMysqlTypesCntSql = "SELECT COUNT(1) AS cnt, c_bool, c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float , c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types GROUP BY c_bool , c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_json, c_json_string_override, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob LIMIT 1 "; public class GetMysqlTypesCntRow { public long Cnt { get; set; } @@ -840,7 +848,7 @@ public async Task GetMysqlTypesCnt() return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql, transaction: this.Transaction); } - private const string GetMysqlFunctionsSql = "SELECT MAX(c_int) AS max_int, MAX(c_varchar) AS max_varchar, MAX(c_timestamp) AS max_timestamp FROM mysql_types ; SELECT LAST_INSERT_ID ( ) "; + private const string GetMysqlFunctionsSql = "SELECT MAX(c_int) AS max_int, MAX(c_varchar) AS max_varchar, MAX(c_timestamp) AS max_timestamp FROM mysql_types "; public class GetMysqlFunctionsRow { public int? MaxInt { get; set; } @@ -866,7 +874,7 @@ public async Task GetMysqlFunctions() return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql, transaction: this.Transaction); } - private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types; SELECT LAST_INSERT_ID()"; + private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types"; public async Task TruncateMysqlTypes() { if (this.Transaction == null) @@ -887,7 +895,7 @@ public async Task TruncateMysqlTypes() await this.Transaction.Connection.ExecuteAsync(TruncateMysqlTypesSql, transaction: this.Transaction); } - private const string CreateExtendedBioSql = "INSERT INTO extended.bios (author_name, name, bio_type) VALUES (@author_name, @name, @bio_type); SELECT LAST_INSERT_ID()"; + private const string CreateExtendedBioSql = "INSERT INTO extended.bios (author_name, name, bio_type) VALUES (@author_name, @name, @bio_type)"; public class CreateExtendedBioArgs { public string AuthorName { get; set; } @@ -918,7 +926,7 @@ public async Task CreateExtendedBio(CreateExtendedBioArgs args) await this.Transaction.Connection.ExecuteAsync(CreateExtendedBioSql, queryParams, transaction: this.Transaction); } - private const string GetFirstExtendedBioByTypeSql = "SELECT author_name, name, bio_type FROM extended.bios WHERE bio_type = @bio_type LIMIT 1; SELECT LAST_INSERT_ID()"; + private const string GetFirstExtendedBioByTypeSql = "SELECT author_name, name, bio_type FROM extended.bios WHERE bio_type = @bio_type LIMIT 1"; public class GetFirstExtendedBioByTypeRow { public string AuthorName { get; set; } @@ -950,7 +958,7 @@ public async Task GetFirstExtendedBioByType(GetFir return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams, transaction: this.Transaction); } - private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios; SELECT LAST_INSERT_ID()"; + private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios"; public async Task TruncateExtendedBios() { if (this.Transaction == null) diff --git a/examples/MySqlConnectorDapperLegacyExample/request.json b/examples/MySqlConnectorDapperLegacyExample/request.json index 16664b9c..182684f1 100644 --- a/examples/MySqlConnectorDapperLegacyExample/request.json +++ b/examples/MySqlConnectorDapperLegacyExample/request.json @@ -629,7 +629,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT ? OFFSET ?", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -669,6 +669,30 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/MySqlConnectorDapperLegacyExample/request.message b/examples/MySqlConnectorDapperLegacyExample/request.message index 2850406b..23c0ca6f 100644 Binary files a/examples/MySqlConnectorDapperLegacyExample/request.message and b/examples/MySqlConnectorDapperLegacyExample/request.message differ diff --git a/examples/MySqlConnectorExample/QuerySql.cs b/examples/MySqlConnectorExample/QuerySql.cs index ebd2f386..6991ec60 100644 --- a/examples/MySqlConnectorExample/QuerySql.cs +++ b/examples/MySqlConnectorExample/QuerySql.cs @@ -99,9 +99,10 @@ public static QuerySql WithTransaction(MySqlTransaction transaction) return null; } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public readonly record struct ListAuthorsRow(long Id, string Name, string? Bio); - public async Task> ListAuthors() + public readonly record struct ListAuthorsArgs(int Limit, int Offset); + public async Task> ListAuthors(ListAuthorsArgs args) { if (this.Transaction == null) { @@ -110,6 +111,8 @@ public async Task> ListAuthors() await connection.OpenAsync(); using (var command = new MySqlCommand(ListAuthorsSql, connection)) { + command.Parameters.AddWithValue("@limit", args.Limit); + command.Parameters.AddWithValue("@offset", args.Offset); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); @@ -127,6 +130,8 @@ public async Task> ListAuthors() { command.CommandText = ListAuthorsSql; command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@limit", args.Limit); + command.Parameters.AddWithValue("@offset", args.Offset); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); diff --git a/examples/MySqlConnectorExample/request.json b/examples/MySqlConnectorExample/request.json index be3ce032..04a6f3da 100644 --- a/examples/MySqlConnectorExample/request.json +++ b/examples/MySqlConnectorExample/request.json @@ -629,7 +629,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT ? OFFSET ?", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -669,6 +669,30 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/MySqlConnectorExample/request.message b/examples/MySqlConnectorExample/request.message index 4edb5396..25147dde 100644 Binary files a/examples/MySqlConnectorExample/request.message and b/examples/MySqlConnectorExample/request.message differ diff --git a/examples/MySqlConnectorLegacyExample/QuerySql.cs b/examples/MySqlConnectorLegacyExample/QuerySql.cs index f05433cd..4f500e5c 100644 --- a/examples/MySqlConnectorLegacyExample/QuerySql.cs +++ b/examples/MySqlConnectorLegacyExample/QuerySql.cs @@ -108,14 +108,19 @@ public async Task GetAuthor(GetAuthorArgs args) return null; } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public long Id { get; set; } public string Name { get; set; } public string Bio { get; set; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs + { + public int Limit { get; set; } + public int Offset { get; set; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) { if (this.Transaction == null) { @@ -124,6 +129,8 @@ public async Task> ListAuthors() await connection.OpenAsync(); using (var command = new MySqlCommand(ListAuthorsSql, connection)) { + command.Parameters.AddWithValue("@limit", args.Limit); + command.Parameters.AddWithValue("@offset", args.Offset); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); @@ -141,6 +148,8 @@ public async Task> ListAuthors() { command.CommandText = ListAuthorsSql; command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@limit", args.Limit); + command.Parameters.AddWithValue("@offset", args.Offset); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); diff --git a/examples/MySqlConnectorLegacyExample/request.json b/examples/MySqlConnectorLegacyExample/request.json index 067775a4..791be11e 100644 --- a/examples/MySqlConnectorLegacyExample/request.json +++ b/examples/MySqlConnectorLegacyExample/request.json @@ -629,7 +629,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT ? OFFSET ?", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -669,6 +669,30 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/MySqlConnectorLegacyExample/request.message b/examples/MySqlConnectorLegacyExample/request.message index e26f82f3..e7aadc4e 100644 Binary files a/examples/MySqlConnectorLegacyExample/request.message and b/examples/MySqlConnectorLegacyExample/request.message differ diff --git a/examples/NpgsqlDapperExample/QuerySql.cs b/examples/NpgsqlDapperExample/QuerySql.cs index d2d9d1a5..4fa8985d 100644 --- a/examples/NpgsqlDapperExample/QuerySql.cs +++ b/examples/NpgsqlDapperExample/QuerySql.cs @@ -74,27 +74,35 @@ public class GetAuthorArgs return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public required long Id { get; init; } public required string Name { get; init; } public string? Bio { get; init; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs { + public required int Offset { get; init; } + public required int Limit { get; init; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) + { + var queryParams = new Dictionary(); + queryParams.Add("offset", args.Offset); + queryParams.Add("limit", args.Limit); if (this.Transaction == null) { using (var connection = new NpgsqlConnection(ConnectionString)) { - var result = await connection.QueryAsync(ListAuthorsSql); + var result = await connection.QueryAsync(ListAuthorsSql, queryParams); return result.AsList(); } } if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) throw new InvalidOperationException("Transaction is provided, but its connection is null."); - return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio) RETURNING id, name, bio"; diff --git a/examples/NpgsqlDapperExample/request.json b/examples/NpgsqlDapperExample/request.json index 37623228..d4b220e6 100644 --- a/examples/NpgsqlDapperExample/request.json +++ b/examples/NpgsqlDapperExample/request.json @@ -32497,7 +32497,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT $2\nOFFSET $1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -32537,6 +32537,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/NpgsqlDapperExample/request.message b/examples/NpgsqlDapperExample/request.message index 7b1dad8e..d7603cf5 100644 --- a/examples/NpgsqlDapperExample/request.message +++ b/examples/NpgsqlDapperExample/request.message @@ -10211,12 +10211,17 @@ WHERE name = $1 LIMIT 1 GetAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*0, -name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sql× -/SELECT id, name, bio FROM authors -ORDER BY name ListAuthors:many"- +name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sqlº +CSELECT id, name, bio +FROM authors +ORDER BY name +LIMIT $2 +OFFSET $1 ListAuthors:many"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( -bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio: query.sql­ +bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*&" +offset0ÿÿÿÿÿÿÿÿÿ8b integer*%! +limit0ÿÿÿÿÿÿÿÿÿ8b integer: query.sql­ OINSERT INTO authors (id, name, bio) VALUES ($1, $2, $3) RETURNING id, name, bio CreateAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( diff --git a/examples/NpgsqlDapperLegacyExample/QuerySql.cs b/examples/NpgsqlDapperLegacyExample/QuerySql.cs index ed78e97d..740a5a21 100644 --- a/examples/NpgsqlDapperLegacyExample/QuerySql.cs +++ b/examples/NpgsqlDapperLegacyExample/QuerySql.cs @@ -75,27 +75,35 @@ public async Task GetAuthor(GetAuthorArgs args) return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public long Id { get; set; } public string Name { get; set; } public string Bio { get; set; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs { + public int Offset { get; set; } + public int Limit { get; set; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) + { + var queryParams = new Dictionary(); + queryParams.Add("offset", args.Offset); + queryParams.Add("limit", args.Limit); if (this.Transaction == null) { using (var connection = new NpgsqlConnection(ConnectionString)) { - var result = await connection.QueryAsync(ListAuthorsSql); + var result = await connection.QueryAsync(ListAuthorsSql, queryParams); return result.AsList(); } } if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) throw new InvalidOperationException("Transaction is provided, but its connection is null."); - return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio) RETURNING id, name, bio"; diff --git a/examples/NpgsqlDapperLegacyExample/request.json b/examples/NpgsqlDapperLegacyExample/request.json index ccd70c40..f1505a5c 100644 --- a/examples/NpgsqlDapperLegacyExample/request.json +++ b/examples/NpgsqlDapperLegacyExample/request.json @@ -32497,7 +32497,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT $2\nOFFSET $1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -32537,6 +32537,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/NpgsqlDapperLegacyExample/request.message b/examples/NpgsqlDapperLegacyExample/request.message index 1dc66e98..1eeedbbc 100644 --- a/examples/NpgsqlDapperLegacyExample/request.message +++ b/examples/NpgsqlDapperLegacyExample/request.message @@ -10211,12 +10211,17 @@ WHERE name = $1 LIMIT 1 GetAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*0, -name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sql× -/SELECT id, name, bio FROM authors -ORDER BY name ListAuthors:many"- +name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sqlº +CSELECT id, name, bio +FROM authors +ORDER BY name +LIMIT $2 +OFFSET $1 ListAuthors:many"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( -bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio: query.sql­ +bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*&" +offset0ÿÿÿÿÿÿÿÿÿ8b integer*%! +limit0ÿÿÿÿÿÿÿÿÿ8b integer: query.sql­ OINSERT INTO authors (id, name, bio) VALUES ($1, $2, $3) RETURNING id, name, bio CreateAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( diff --git a/examples/NpgsqlExample/QuerySql.cs b/examples/NpgsqlExample/QuerySql.cs index 9da5490e..84a720b7 100644 --- a/examples/NpgsqlExample/QuerySql.cs +++ b/examples/NpgsqlExample/QuerySql.cs @@ -96,9 +96,10 @@ public static QuerySql WithTransaction(NpgsqlTransaction transaction) return null; } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public readonly record struct ListAuthorsRow(long Id, string Name, string? Bio); - public async Task> ListAuthors() + public readonly record struct ListAuthorsArgs(int Offset, int Limit); + public async Task> ListAuthors(ListAuthorsArgs args) { if (this.Transaction == null) { @@ -106,6 +107,8 @@ public async Task> ListAuthors() { using (var command = connection.CreateCommand(ListAuthorsSql)) { + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); @@ -123,6 +126,8 @@ public async Task> ListAuthors() { command.CommandText = ListAuthorsSql; command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); diff --git a/examples/NpgsqlExample/request.json b/examples/NpgsqlExample/request.json index e9dc600e..a5bd3436 100644 --- a/examples/NpgsqlExample/request.json +++ b/examples/NpgsqlExample/request.json @@ -32497,7 +32497,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT $2\nOFFSET $1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -32537,6 +32537,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/NpgsqlExample/request.message b/examples/NpgsqlExample/request.message index 361842de..ff950149 100644 --- a/examples/NpgsqlExample/request.message +++ b/examples/NpgsqlExample/request.message @@ -10211,12 +10211,17 @@ WHERE name = $1 LIMIT 1 GetAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*0, -name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sql× -/SELECT id, name, bio FROM authors -ORDER BY name ListAuthors:many"- +name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sqlº +CSELECT id, name, bio +FROM authors +ORDER BY name +LIMIT $2 +OFFSET $1 ListAuthors:many"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( -bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio: query.sql­ +bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*&" +offset0ÿÿÿÿÿÿÿÿÿ8b integer*%! +limit0ÿÿÿÿÿÿÿÿÿ8b integer: query.sql­ OINSERT INTO authors (id, name, bio) VALUES ($1, $2, $3) RETURNING id, name, bio CreateAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( diff --git a/examples/NpgsqlLegacyExample/QuerySql.cs b/examples/NpgsqlLegacyExample/QuerySql.cs index 04aa1fc3..f865bfb3 100644 --- a/examples/NpgsqlLegacyExample/QuerySql.cs +++ b/examples/NpgsqlLegacyExample/QuerySql.cs @@ -105,14 +105,19 @@ public async Task GetAuthor(GetAuthorArgs args) return null; } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public long Id { get; set; } public string Name { get; set; } public string Bio { get; set; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs + { + public int Offset { get; set; } + public int Limit { get; set; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) { if (this.Transaction == null) { @@ -120,6 +125,8 @@ public async Task> ListAuthors() { using (var command = connection.CreateCommand(ListAuthorsSql)) { + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); @@ -137,6 +144,8 @@ public async Task> ListAuthors() { command.CommandText = ListAuthorsSql; command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); diff --git a/examples/NpgsqlLegacyExample/request.json b/examples/NpgsqlLegacyExample/request.json index f1fda4a9..152879cd 100644 --- a/examples/NpgsqlLegacyExample/request.json +++ b/examples/NpgsqlLegacyExample/request.json @@ -32497,7 +32497,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio \nFROM authors\nORDER BY name\nLIMIT $2\nOFFSET $1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -32537,6 +32537,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/NpgsqlLegacyExample/request.message b/examples/NpgsqlLegacyExample/request.message index a0a78cd0..e6aa12d9 100644 --- a/examples/NpgsqlLegacyExample/request.message +++ b/examples/NpgsqlLegacyExample/request.message @@ -10211,12 +10211,17 @@ WHERE name = $1 LIMIT 1 GetAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*0, -name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sql× -/SELECT id, name, bio FROM authors -ORDER BY name ListAuthors:many"- +name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname: query.sqlº +CSELECT id, name, bio +FROM authors +ORDER BY name +LIMIT $2 +OFFSET $1 ListAuthors:many"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( -bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio: query.sql­ +bio0ÿÿÿÿÿÿÿÿÿR authorsbtextzbio*&" +offset0ÿÿÿÿÿÿÿÿÿ8b integer*%! +limit0ÿÿÿÿÿÿÿÿÿ8b integer: query.sql­ OINSERT INTO authors (id, name, bio) VALUES ($1, $2, $3) RETURNING id, name, bio CreateAuthor:one"- id0ÿÿÿÿÿÿÿÿÿR authorsb  bigserialzid", name0ÿÿÿÿÿÿÿÿÿR authorsbtextzname"( diff --git a/examples/SqliteDapperExample/QuerySql.cs b/examples/SqliteDapperExample/QuerySql.cs index 5709bfa1..46afa735 100644 --- a/examples/SqliteDapperExample/QuerySql.cs +++ b/examples/SqliteDapperExample/QuerySql.cs @@ -69,27 +69,35 @@ public class GetAuthorArgs return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public required int Id { get; init; } public required string Name { get; init; } public string? Bio { get; init; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs { + public required int Offset { get; init; } + public required int Limit { get; init; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) + { + var queryParams = new Dictionary(); + queryParams.Add("offset", args.Offset); + queryParams.Add("limit", args.Limit); if (this.Transaction == null) { using (var connection = new SqliteConnection(ConnectionString)) { - var result = await connection.QueryAsync(ListAuthorsSql); + var result = await connection.QueryAsync(ListAuthorsSql, queryParams); return result.AsList(); } } if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) throw new InvalidOperationException("Transaction is provided, but its connection is null."); - return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio)"; diff --git a/examples/SqliteDapperExample/request.json b/examples/SqliteDapperExample/request.json index d856da0f..b26edf17 100644 --- a/examples/SqliteDapperExample/request.json +++ b/examples/SqliteDapperExample/request.json @@ -225,7 +225,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio\nFROM authors\nORDER BY name\nLIMIT ?2 OFFSET ?1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -265,6 +265,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/SqliteDapperExample/request.message b/examples/SqliteDapperExample/request.message index 4c60fab2..a02c8d33 100644 Binary files a/examples/SqliteDapperExample/request.message and b/examples/SqliteDapperExample/request.message differ diff --git a/examples/SqliteDapperLegacyExample/QuerySql.cs b/examples/SqliteDapperLegacyExample/QuerySql.cs index 4eb69a30..0ae3b549 100644 --- a/examples/SqliteDapperLegacyExample/QuerySql.cs +++ b/examples/SqliteDapperLegacyExample/QuerySql.cs @@ -70,27 +70,35 @@ public async Task GetAuthor(GetAuthorArgs args) return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public int Id { get; set; } public string Name { get; set; } public string Bio { get; set; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs { + public int Offset { get; set; } + public int Limit { get; set; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) + { + var queryParams = new Dictionary(); + queryParams.Add("offset", args.Offset); + queryParams.Add("limit", args.Limit); if (this.Transaction == null) { using (var connection = new SqliteConnection(ConnectionString)) { - var result = await connection.QueryAsync(ListAuthorsSql); + var result = await connection.QueryAsync(ListAuthorsSql, queryParams); return result.AsList(); } } if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) throw new InvalidOperationException("Transaction is provided, but its connection is null."); - return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio)"; diff --git a/examples/SqliteDapperLegacyExample/request.json b/examples/SqliteDapperLegacyExample/request.json index aa0b7b65..d27f139d 100644 --- a/examples/SqliteDapperLegacyExample/request.json +++ b/examples/SqliteDapperLegacyExample/request.json @@ -225,7 +225,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio\nFROM authors\nORDER BY name\nLIMIT ?2 OFFSET ?1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -265,6 +265,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/SqliteDapperLegacyExample/request.message b/examples/SqliteDapperLegacyExample/request.message index 907a6da7..4e6a0021 100644 Binary files a/examples/SqliteDapperLegacyExample/request.message and b/examples/SqliteDapperLegacyExample/request.message differ diff --git a/examples/SqliteExample/QuerySql.cs b/examples/SqliteExample/QuerySql.cs index 2cc5b4e6..0123d6ee 100644 --- a/examples/SqliteExample/QuerySql.cs +++ b/examples/SqliteExample/QuerySql.cs @@ -92,9 +92,10 @@ public static QuerySql WithTransaction(SqliteTransaction transaction) return null; } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public readonly record struct ListAuthorsRow(int Id, string Name, string? Bio); - public async Task> ListAuthors() + public readonly record struct ListAuthorsArgs(int Offset, int Limit); + public async Task> ListAuthors(ListAuthorsArgs args) { if (this.Transaction == null) { @@ -103,6 +104,8 @@ public async Task> ListAuthors() await connection.OpenAsync(); using (var command = new SqliteCommand(ListAuthorsSql, connection)) { + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); @@ -120,6 +123,8 @@ public async Task> ListAuthors() { command.CommandText = ListAuthorsSql; command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); diff --git a/examples/SqliteExample/request.json b/examples/SqliteExample/request.json index ac3a512c..f5c7e569 100644 --- a/examples/SqliteExample/request.json +++ b/examples/SqliteExample/request.json @@ -225,7 +225,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio\nFROM authors\nORDER BY name\nLIMIT ?2 OFFSET ?1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -265,6 +265,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/SqliteExample/request.message b/examples/SqliteExample/request.message index 17ee933e..9ed6b861 100644 Binary files a/examples/SqliteExample/request.message and b/examples/SqliteExample/request.message differ diff --git a/examples/SqliteLegacyExample/QuerySql.cs b/examples/SqliteLegacyExample/QuerySql.cs index 03f3fd45..2f13abfc 100644 --- a/examples/SqliteLegacyExample/QuerySql.cs +++ b/examples/SqliteLegacyExample/QuerySql.cs @@ -101,14 +101,19 @@ public async Task GetAuthor(GetAuthorArgs args) return null; } - private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; + private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name LIMIT @limit OFFSET @offset "; public class ListAuthorsRow { public int Id { get; set; } public string Name { get; set; } public string Bio { get; set; } }; - public async Task> ListAuthors() + public class ListAuthorsArgs + { + public int Offset { get; set; } + public int Limit { get; set; } + }; + public async Task> ListAuthors(ListAuthorsArgs args) { if (this.Transaction == null) { @@ -117,6 +122,8 @@ public async Task> ListAuthors() await connection.OpenAsync(); using (var command = new SqliteCommand(ListAuthorsSql, connection)) { + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); @@ -134,6 +141,8 @@ public async Task> ListAuthors() { command.CommandText = ListAuthorsSql; command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@offset", args.Offset); + command.Parameters.AddWithValue("@limit", args.Limit); using (var reader = await command.ExecuteReaderAsync()) { var result = new List(); diff --git a/examples/SqliteLegacyExample/request.json b/examples/SqliteLegacyExample/request.json index 37b29922..10861a07 100644 --- a/examples/SqliteLegacyExample/request.json +++ b/examples/SqliteLegacyExample/request.json @@ -225,7 +225,7 @@ "filename": "query.sql" }, { - "text": "SELECT id, name, bio FROM authors\nORDER BY name", + "text": "SELECT id, name, bio\nFROM authors\nORDER BY name\nLIMIT ?2 OFFSET ?1", "name": "ListAuthors", "cmd": ":many", "columns": [ @@ -265,6 +265,32 @@ "originalName": "bio" } ], + "parameters": [ + { + "number": 1, + "column": { + "name": "offset", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + }, + { + "number": 2, + "column": { + "name": "limit", + "notNull": true, + "length": -1, + "isNamedParam": true, + "type": { + "name": "integer" + } + } + } + ], "filename": "query.sql" }, { diff --git a/examples/SqliteLegacyExample/request.message b/examples/SqliteLegacyExample/request.message index edc0f0d5..23341d27 100644 Binary files a/examples/SqliteLegacyExample/request.message and b/examples/SqliteLegacyExample/request.message differ diff --git a/examples/config/mysql/query.sql b/examples/config/mysql/query.sql index a92c49d9..33ad29d4 100644 --- a/examples/config/mysql/query.sql +++ b/examples/config/mysql/query.sql @@ -2,8 +2,10 @@ SELECT * FROM authors WHERE name = ? LIMIT 1; -- name: ListAuthors :many -SELECT * FROM authors -ORDER BY name; +SELECT * +FROM authors +ORDER BY name +LIMIT ? OFFSET ?; -- name: CreateAuthor :exec INSERT INTO authors (id, name, bio) VALUES (?, ?, ?); diff --git a/examples/config/postgresql/query.sql b/examples/config/postgresql/query.sql index 762affe7..670850cb 100644 --- a/examples/config/postgresql/query.sql +++ b/examples/config/postgresql/query.sql @@ -3,8 +3,11 @@ SELECT * FROM authors WHERE name = $1 LIMIT 1; -- name: ListAuthors :many -SELECT * FROM authors -ORDER BY name; +SELECT * +FROM authors +ORDER BY name +LIMIT sqlc.arg('limit') +OFFSET sqlc.arg('offset'); -- name: CreateAuthor :one INSERT INTO authors (id, name, bio) VALUES ($1, $2, $3) RETURNING *; diff --git a/examples/config/sqlite/query.sql b/examples/config/sqlite/query.sql index 9e9c8803..cf874286 100644 --- a/examples/config/sqlite/query.sql +++ b/examples/config/sqlite/query.sql @@ -3,8 +3,10 @@ SELECT * FROM authors WHERE name = ? LIMIT 1; -- name: ListAuthors :many -SELECT * FROM authors -ORDER BY name; +SELECT * +FROM authors +ORDER BY name +LIMIT sqlc.arg('limit') OFFSET sqlc.arg('offset'); -- name: CreateAuthor :exec INSERT INTO authors (id, name, bio) VALUES (?, ?, ?);