From 56fe89ee4c859f9481573bb5c33fd1798474d336 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Tue, 15 Aug 2023 13:08:15 +0100 Subject: [PATCH] example for https://github.com/DapperLib/Dapper/issues/1945 --- .../Interceptors/GlobalFetchSize.input.cs | 42 +++++++ .../Interceptors/GlobalFetchSize.output.cs | 106 ++++++++++++++++++ .../GlobalFetchSize.output.netfx.cs | 106 ++++++++++++++++++ .../GlobalFetchSize.output.netfx.txt | 4 + .../Interceptors/GlobalFetchSize.output.txt | 4 + 5 files changed, 262 insertions(+) create mode 100644 test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.input.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs create mode 100644 test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.txt create mode 100644 test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.txt diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.input.cs b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.input.cs new file mode 100644 index 00000000..2fae24ca --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.input.cs @@ -0,0 +1,42 @@ +using Dapper; +using SomeApp; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using Oracle.ManagedDataAccess.Client; + +[module: DapperAot] +[module: CommandFactory>] + +namespace SomeApp +{ + public static class Foo + { + static List SomeCode(DbConnection connection, string bar) + => connection.Query("def", new { Foo = 12, bar }).AsList(); + } + public class SomeQueryType { /* ... */ } + + public static class GlobalSettings + { + public static int DefaultFetchSize { get; set; } = 131072; // from Oracle docs + } + public interface IDynamicFetchSize + { + int FetchSize { get; } + } + + internal abstract class GlobalFetchSizeCommandFactory : CommandFactory + { + public override DbCommand GetCommand(DbConnection connection, string sql, CommandType commandType, T args) + { + var cmd = base.GetCommand(connection, sql, commandType, args); + if (cmd is OracleCommand oracle) + { + oracle.FetchSize = args is IDynamicFetchSize d ? d.FetchSize : GlobalSettings.DefaultFetchSize; + } + return cmd; + } + } + +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs new file mode 100644 index 00000000..c4eaaa99 --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs @@ -0,0 +1,106 @@ +#nullable enable +file static class DapperGeneratedInterceptors +{ + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\GlobalFetchSize.input.cs", 16, 27)] + internal static global::System.Collections.Generic.IEnumerable Query0(this global::System.Data.IDbConnection cnn, string sql, object param, global::System.Data.IDbTransaction transaction, bool buffered, int? commandTimeout, global::System.Data.CommandType? commandType) + { + // Query, TypedResult, HasParameters, Buffered, StoredProcedure + // takes parameter: + // parameter map: (everything) + // returns data: global::SomeApp.SomeQueryType + global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); + global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.StoredProcedure); + global::System.Diagnostics.Debug.Assert(buffered is true); + global::System.Diagnostics.Debug.Assert(param is not null); + + return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.StoredProcedure, commandTimeout.GetValueOrDefault(), CommandFactory0.Instance).QueryBuffered(param, RowFactory0.Instance); + + } + + private class CommonCommandFactory : global::SomeApp.GlobalFetchSizeCommandFactory + { + 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 DefaultCommandFactory = new(); + + private sealed class RowFactory0 : global::Dapper.RowFactory + { + internal static readonly RowFactory0 Instance = new(); + private RowFactory0() {} + public override global::SomeApp.SomeQueryType Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan tokens, int columnOffset, object? state) + { + global::SomeApp.SomeQueryType result = new(); + return result; + + } + + } + + private sealed class CommandFactory0 : CommonCommandFactory // + { + internal static readonly CommandFactory0 Instance = new(); + public override void AddParameters(global::System.Data.Common.DbCommand cmd, object? args) + { + var typed = Cast(args, static () => new { Foo = default(int), bar = default(string)! }); // expected shape + var ps = cmd.Parameters; + global::System.Data.Common.DbParameter p; + p = cmd.CreateParameter(); + p.ParameterName = "Foo"; + p.DbType = global::System.Data.DbType.Int32; + p.Direction = global::System.Data.ParameterDirection.Input; + p.Value = AsValue(typed.Foo); + ps.Add(p); + + p = cmd.CreateParameter(); + p.ParameterName = "bar"; + p.DbType = global::System.Data.DbType.String; + p.Size = -1; + p.Direction = global::System.Data.ParameterDirection.Input; + p.Value = AsValue(typed.bar); + ps.Add(p); + + } + public override void UpdateParameters(global::System.Data.Common.DbCommand cmd, object? args) + { + var typed = Cast(args, static () => new { Foo = default(int), bar = default(string)! }); // expected shape + var ps = cmd.Parameters; + ps[0].Value = AsValue(typed.Foo); + ps[1].Value = AsValue(typed.bar); + + } + public override bool CanPrepare => true; + + } + + +} +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; + } + } +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs new file mode 100644 index 00000000..c4eaaa99 --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs @@ -0,0 +1,106 @@ +#nullable enable +file static class DapperGeneratedInterceptors +{ + [global::System.Runtime.CompilerServices.InterceptsLocationAttribute("Interceptors\\GlobalFetchSize.input.cs", 16, 27)] + internal static global::System.Collections.Generic.IEnumerable Query0(this global::System.Data.IDbConnection cnn, string sql, object param, global::System.Data.IDbTransaction transaction, bool buffered, int? commandTimeout, global::System.Data.CommandType? commandType) + { + // Query, TypedResult, HasParameters, Buffered, StoredProcedure + // takes parameter: + // parameter map: (everything) + // returns data: global::SomeApp.SomeQueryType + global::System.Diagnostics.Debug.Assert(!string.IsNullOrWhiteSpace(sql)); + global::System.Diagnostics.Debug.Assert((commandType ?? global::Dapper.DapperAotExtensions.GetCommandType(sql)) == global::System.Data.CommandType.StoredProcedure); + global::System.Diagnostics.Debug.Assert(buffered is true); + global::System.Diagnostics.Debug.Assert(param is not null); + + return global::Dapper.DapperAotExtensions.Command(cnn, transaction, sql, global::System.Data.CommandType.StoredProcedure, commandTimeout.GetValueOrDefault(), CommandFactory0.Instance).QueryBuffered(param, RowFactory0.Instance); + + } + + private class CommonCommandFactory : global::SomeApp.GlobalFetchSizeCommandFactory + { + 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 DefaultCommandFactory = new(); + + private sealed class RowFactory0 : global::Dapper.RowFactory + { + internal static readonly RowFactory0 Instance = new(); + private RowFactory0() {} + public override global::SomeApp.SomeQueryType Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan tokens, int columnOffset, object? state) + { + global::SomeApp.SomeQueryType result = new(); + return result; + + } + + } + + private sealed class CommandFactory0 : CommonCommandFactory // + { + internal static readonly CommandFactory0 Instance = new(); + public override void AddParameters(global::System.Data.Common.DbCommand cmd, object? args) + { + var typed = Cast(args, static () => new { Foo = default(int), bar = default(string)! }); // expected shape + var ps = cmd.Parameters; + global::System.Data.Common.DbParameter p; + p = cmd.CreateParameter(); + p.ParameterName = "Foo"; + p.DbType = global::System.Data.DbType.Int32; + p.Direction = global::System.Data.ParameterDirection.Input; + p.Value = AsValue(typed.Foo); + ps.Add(p); + + p = cmd.CreateParameter(); + p.ParameterName = "bar"; + p.DbType = global::System.Data.DbType.String; + p.Size = -1; + p.Direction = global::System.Data.ParameterDirection.Input; + p.Value = AsValue(typed.bar); + ps.Add(p); + + } + public override void UpdateParameters(global::System.Data.Common.DbCommand cmd, object? args) + { + var typed = Cast(args, static () => new { Foo = default(int), bar = default(string)! }); // expected shape + var ps = cmd.Parameters; + ps[0].Value = AsValue(typed.Foo); + ps[1].Value = AsValue(typed.bar); + + } + public override bool CanPrepare => true; + + } + + +} +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; + } + } +} \ No newline at end of file diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.txt b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.txt new file mode 100644 index 00000000..5f233c5d --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.txt @@ -0,0 +1,4 @@ +Generator produced 1 diagnostics: + +Hidden DAP000 L1 C1 +Dapper.AOT handled 1 of 1 enabled call-sites using 1 interceptors, 1 commands and 1 readers diff --git a/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.txt b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.txt new file mode 100644 index 00000000..5f233c5d --- /dev/null +++ b/test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.txt @@ -0,0 +1,4 @@ +Generator produced 1 diagnostics: + +Hidden DAP000 L1 C1 +Dapper.AOT handled 1 of 1 enabled call-sites using 1 interceptors, 1 commands and 1 readers