-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* minimal repro of #86 * handle top-level statements (also: make the test pass on netfx)
- Loading branch information
Showing
8 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
test/Dapper.AOT.Test/Interceptors/TopLevelStatements.input.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using Dapper; | ||
using System; | ||
using System.Data.Common; | ||
using System.Threading.Tasks; | ||
|
||
|
||
[module: DapperAot] | ||
|
||
#if !NETFRAMEWORK | ||
Console.WriteLine(System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported ? "Running with JIT" : "Running with AOT"); | ||
#endif | ||
|
||
// Dapper.AOT, at least at the moment (it was released like 4 days ago), doesn't seem to be able to handle things if we don't put it in a class | ||
app.MapGet("/", async (HttpContext context, SqlConnectionFactory sqlConnectionFactory, Stack stack) => | ||
{ | ||
#if !NETFRAMEWORK | ||
await | ||
#endif | ||
using var connection = sqlConnectionFactory(); | ||
var item = await connection.QuerySingleAsync<SomeThing>("SELECT SomeId, SomeText FROM SomeThing LIMIT 1"); | ||
//context.Response.Headers["stack"] = stack.Name; | ||
return Results.Ok(item); | ||
}); | ||
|
||
public static class Handlers | ||
{ | ||
public static async Task<IResult> Root(HttpContext context, SqlConnectionFactory sqlConnectionFactory, Stack stack) | ||
{ | ||
#if !NETFRAMEWORK | ||
await | ||
#endif | ||
using var connection = sqlConnectionFactory(); | ||
var item = await connection.QuerySingleAsync<SomeThing>("SELECT SomeId, SomeText FROM SomeThing LIMIT 1"); | ||
// context.Response.Headers["stack"] = stack.Name; | ||
return Results.Ok(item); | ||
} | ||
} | ||
|
||
public record SomeThing(int SomeId, string SomeText); | ||
|
||
public record Stack(string Name); | ||
|
||
|
||
// spoof enough fake http code to build | ||
public static class app | ||
{ | ||
public static void MapGet(string path, Delegate handler) => throw new NotImplementedException(); | ||
} | ||
|
||
public delegate DbConnection SqlConnectionFactory(); | ||
public interface IResult { } | ||
public static class Results | ||
{ | ||
public static IResult Ok(object whatever) => throw new NotImplementedException(); | ||
} | ||
public class HttpContext {} | ||
|
||
#if NETFRAMEWORK | ||
namespace System.Runtime.CompilerServices | ||
{ | ||
file static class IsExternalInit | ||
{ | ||
} | ||
} | ||
#endif |
114 changes: 114 additions & 0 deletions
114
test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
#nullable enable | ||
namespace Dapper.AOT // interceptors must be in a known namespace | ||
{ | ||
file static class DapperGeneratedInterceptors | ||
{ | ||
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TopLevelStatements.input.cs", 20, 33)] | ||
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TopLevelStatements.input.cs", 33, 37)] | ||
internal static global::System.Threading.Tasks.Task<global::SomeThing> QuerySingleAsync0(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType) | ||
{ | ||
// Query, Async, TypedResult, SingleRow, Text, AtLeastOne, AtMostOne, BindResultsByName | ||
// returns data: global::SomeThing | ||
global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); | ||
global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text); | ||
global::System.Diagnostics.Debug.Assert(param is null); | ||
|
||
return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), DefaultCommandFactory).QuerySingleAsync(param, RowFactory0.Instance); | ||
|
||
} | ||
|
||
private class CommonCommandFactory<T> : global::Dapper.CommandFactory<T> | ||
{ | ||
public override global::System.Data.Common.DbCommand GetCommand(global::System.Data.Common.DbConnection connection, string sql, global::System.Data.CommandType commandType, T args) | ||
{ | ||
var cmd = base.GetCommand(connection, sql, commandType, args); | ||
// apply special per-provider command initialization logic for OracleCommand | ||
if (cmd is global::Oracle.ManagedDataAccess.Client.OracleCommand cmd0) | ||
{ | ||
cmd0.BindByName = true; | ||
cmd0.InitialLONGFetchSize = -1; | ||
|
||
} | ||
return cmd; | ||
} | ||
|
||
} | ||
|
||
private static readonly CommonCommandFactory<object?> DefaultCommandFactory = new(); | ||
|
||
private sealed class RowFactory0 : global::Dapper.RowFactory<global::SomeThing> | ||
{ | ||
internal static readonly RowFactory0 Instance = new(); | ||
private RowFactory0() {} | ||
public override object? Tokenize(global::System.Data.Common.DbDataReader reader, global::System.Span<int> tokens, int columnOffset) | ||
{ | ||
for (int i = 0; i < tokens.Length; i++) | ||
{ | ||
int token = -1; | ||
var name = reader.GetName(columnOffset); | ||
var type = reader.GetFieldType(columnOffset); | ||
switch (NormalizedHash(name)) | ||
{ | ||
case 3328690628U when NormalizedEquals(name, "someid"): | ||
token = type == typeof(int) ? 0 : 2; // two tokens for right-typed and type-flexible | ||
break; | ||
case 1017211458U when NormalizedEquals(name, "sometext"): | ||
token = type == typeof(string) ? 1 : 3; | ||
break; | ||
|
||
} | ||
tokens[i] = token; | ||
columnOffset++; | ||
|
||
} | ||
return null; | ||
} | ||
public override global::SomeThing Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan<int> tokens, int columnOffset, object? state) | ||
{ | ||
int value0 = default; | ||
string? value1 = default; | ||
foreach (var token in tokens) | ||
{ | ||
switch (token) | ||
{ | ||
case 0: | ||
value0 = reader.GetInt32(columnOffset); | ||
break; | ||
case 2: | ||
value0 = GetValue<int>(reader, columnOffset); | ||
break; | ||
case 1: | ||
value1 = reader.IsDBNull(columnOffset) ? (string?)null : reader.GetString(columnOffset); | ||
break; | ||
case 3: | ||
value1 = reader.IsDBNull(columnOffset) ? (string?)null : GetValue<string>(reader, columnOffset); | ||
break; | ||
|
||
} | ||
columnOffset++; | ||
|
||
} | ||
return new global::SomeThing(value0, value1); | ||
} | ||
} | ||
|
||
|
||
} | ||
} | ||
namespace System.Runtime.CompilerServices | ||
{ | ||
// this type is needed by the compiler to implement interceptors - it doesn't need to | ||
// come from the runtime itself, though | ||
|
||
[global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate | ||
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] | ||
sealed file class InterceptsLocationAttribute : global::System.Attribute | ||
{ | ||
public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) | ||
{ | ||
_ = path; | ||
_ = lineNumber; | ||
_ = columnNumber; | ||
} | ||
} | ||
} |
114 changes: 114 additions & 0 deletions
114
test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.netfx.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
#nullable enable | ||
namespace Dapper.AOT // interceptors must be in a known namespace | ||
{ | ||
file static class DapperGeneratedInterceptors | ||
{ | ||
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TopLevelStatements.input.cs", 20, 33)] | ||
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\TopLevelStatements.input.cs", 33, 37)] | ||
internal static global::System.Threading.Tasks.Task<global::SomeThing> QuerySingleAsync0(this global::System.Data.IDbConnection cnn, string sql, object? param, global::System.Data.IDbTransaction? transaction, int? commandTimeout, global::System.Data.CommandType? commandType) | ||
{ | ||
// Query, Async, TypedResult, SingleRow, Text, AtLeastOne, AtMostOne, BindResultsByName | ||
// returns data: global::SomeThing | ||
global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); | ||
global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.Text); | ||
global::System.Diagnostics.Debug.Assert(param is null); | ||
|
||
return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.Text, commandTimeout.GetValueOrDefault(), DefaultCommandFactory).QuerySingleAsync(param, RowFactory0.Instance); | ||
|
||
} | ||
|
||
private class CommonCommandFactory<T> : global::Dapper.CommandFactory<T> | ||
{ | ||
public override global::System.Data.Common.DbCommand GetCommand(global::System.Data.Common.DbConnection connection, string sql, global::System.Data.CommandType commandType, T args) | ||
{ | ||
var cmd = base.GetCommand(connection, sql, commandType, args); | ||
// apply special per-provider command initialization logic for OracleCommand | ||
if (cmd is global::Oracle.ManagedDataAccess.Client.OracleCommand cmd0) | ||
{ | ||
cmd0.BindByName = true; | ||
cmd0.InitialLONGFetchSize = -1; | ||
|
||
} | ||
return cmd; | ||
} | ||
|
||
} | ||
|
||
private static readonly CommonCommandFactory<object?> DefaultCommandFactory = new(); | ||
|
||
private sealed class RowFactory0 : global::Dapper.RowFactory<global::SomeThing> | ||
{ | ||
internal static readonly RowFactory0 Instance = new(); | ||
private RowFactory0() {} | ||
public override object? Tokenize(global::System.Data.Common.DbDataReader reader, global::System.Span<int> tokens, int columnOffset) | ||
{ | ||
for (int i = 0; i < tokens.Length; i++) | ||
{ | ||
int token = -1; | ||
var name = reader.GetName(columnOffset); | ||
var type = reader.GetFieldType(columnOffset); | ||
switch (NormalizedHash(name)) | ||
{ | ||
case 3328690628U when NormalizedEquals(name, "someid"): | ||
token = type == typeof(int) ? 0 : 2; // two tokens for right-typed and type-flexible | ||
break; | ||
case 1017211458U when NormalizedEquals(name, "sometext"): | ||
token = type == typeof(string) ? 1 : 3; | ||
break; | ||
|
||
} | ||
tokens[i] = token; | ||
columnOffset++; | ||
|
||
} | ||
return null; | ||
} | ||
public override global::SomeThing Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan<int> tokens, int columnOffset, object? state) | ||
{ | ||
int value0 = default; | ||
string? value1 = default; | ||
foreach (var token in tokens) | ||
{ | ||
switch (token) | ||
{ | ||
case 0: | ||
value0 = reader.GetInt32(columnOffset); | ||
break; | ||
case 2: | ||
value0 = GetValue<int>(reader, columnOffset); | ||
break; | ||
case 1: | ||
value1 = reader.IsDBNull(columnOffset) ? (string?)null : reader.GetString(columnOffset); | ||
break; | ||
case 3: | ||
value1 = reader.IsDBNull(columnOffset) ? (string?)null : GetValue<string>(reader, columnOffset); | ||
break; | ||
|
||
} | ||
columnOffset++; | ||
|
||
} | ||
return new global::SomeThing(value0, value1); | ||
} | ||
} | ||
|
||
|
||
} | ||
} | ||
namespace System.Runtime.CompilerServices | ||
{ | ||
// this type is needed by the compiler to implement interceptors - it doesn't need to | ||
// come from the runtime itself, though | ||
|
||
[global::System.Diagnostics.Conditional("DEBUG")] // not needed post-build, so: evaporate | ||
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)] | ||
sealed file class InterceptsLocationAttribute : global::System.Attribute | ||
{ | ||
public InterceptsLocationAttribute(string path, int lineNumber, int columnNumber) | ||
{ | ||
_ = path; | ||
_ = lineNumber; | ||
_ = columnNumber; | ||
} | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.netfx.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Generator produced 1 diagnostics: | ||
|
||
Hidden DAP000 L1 C1 | ||
Dapper.AOT handled 2 of 2 possible call-sites using 1 interceptors, 0 commands and 1 readers |
4 changes: 4 additions & 0 deletions
4
test/Dapper.AOT.Test/Interceptors/TopLevelStatements.output.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Generator produced 1 diagnostics: | ||
|
||
Hidden DAP000 L1 C1 | ||
Dapper.AOT handled 2 of 2 possible call-sites using 1 interceptors, 0 commands and 1 readers |