Skip to content

Commit

Permalink
example for DapperLib/Dapper#1945
Browse files Browse the repository at this point in the history
  • Loading branch information
mgravell committed Aug 15, 2023
1 parent b70f245 commit 56fe89e
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 0 deletions.
42 changes: 42 additions & 0 deletions test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.input.cs
Original file line number Diff line number Diff line change
@@ -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<GlobalFetchSizeCommandFactory<object>>]

namespace SomeApp
{
public static class Foo
{
static List<SomeQueryType> SomeCode(DbConnection connection, string bar)
=> connection.Query<SomeQueryType>("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<T> : CommandFactory<T>
{
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;
}
}

}
106 changes: 106 additions & 0 deletions test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.cs
Original file line number Diff line number Diff line change
@@ -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<global::SomeApp.SomeQueryType> 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: <anonymous type: int Foo, string bar>
// 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<T> : global::SomeApp.GlobalFetchSizeCommandFactory<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::SomeApp.SomeQueryType>
{
internal static readonly RowFactory0 Instance = new();
private RowFactory0() {}
public override global::SomeApp.SomeQueryType Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan<int> tokens, int columnOffset, object? state)
{
global::SomeApp.SomeQueryType result = new();
return result;

}

}

private sealed class CommandFactory0 : CommonCommandFactory<object?> // <anonymous type: int Foo, string bar>
{
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;
}
}
}
106 changes: 106 additions & 0 deletions test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.netfx.cs
Original file line number Diff line number Diff line change
@@ -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<global::SomeApp.SomeQueryType> 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: <anonymous type: int Foo, string bar>
// 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<T> : global::SomeApp.GlobalFetchSizeCommandFactory<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::SomeApp.SomeQueryType>
{
internal static readonly RowFactory0 Instance = new();
private RowFactory0() {}
public override global::SomeApp.SomeQueryType Read(global::System.Data.Common.DbDataReader reader, global::System.ReadOnlySpan<int> tokens, int columnOffset, object? state)
{
global::SomeApp.SomeQueryType result = new();
return result;

}

}

private sealed class CommandFactory0 : CommonCommandFactory<object?> // <anonymous type: int Foo, string bar>
{
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;
}
}
}
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 1 of 1 enabled call-sites using 1 interceptors, 1 commands and 1 readers
4 changes: 4 additions & 0 deletions test/Dapper.AOT.Test/Interceptors/GlobalFetchSize.output.txt
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 1 of 1 enabled call-sites using 1 interceptors, 1 commands and 1 readers

0 comments on commit 56fe89e

Please sign in to comment.