mirror of
https://github.com/DapperLib/Dapper.git
synced 2026-10-18 22:31:08 +08:00
aecffecae1
* attempt NRT makeover - annotate NRTs on GridReader API - add protected access to some of the GridReader internals - switch GridReader callbacks to be more type-independent docs lib updates; deal with yellow warnings and test failures (SQL server certs and cancellation surfacing differently) fix break simplify proposed GridReader changes to protected OnBeforeGrid and OnAfterGrid[Async] Builds: Bump library versions (#1935) Tests: Upgrade dependencies for Dependabot (#1936) I'll do a pass at all of these later, but getting CVE versions out of the pipe. Resolving 4 alerts here: https://github.com/DapperLib/Dapper/security/dependabot merge and lib updates allow Identity to be constructed on-the-fly inside GridReader fix build warnings include readme rev minor - enable [SkipLocalsInit] everywhere - use NET5_0_OR_GREATER for remoting check # Conflicts: # Dapper/CommandDefinition.cs # Dapper/DefaultTypeMap.cs # Dapper/SqlMapper.Async.cs # Dapper/SqlMapper.IDataReader.cs # Dapper/SqlMapper.Link.cs # Dapper/SqlMapper.cs # Directory.Build.props * shipped, not unshipped * fixup SqlBuilder; use is null / is not null * use central package management (#1949) * Nullable test tweaks * Nuget: let's just remove it! * 2 test fixes from review * fix FindExplicitConstructor * add GetPropertySetterOrThrow * fix NRT on FindConstructor * DapperRow: value is object? * use NotNullWhen * make constructor problem more obvious * test fixes --------- Co-authored-by: Nick Craver <nrcraver@gmail.com>
236 lines
9.0 KiB
C#
236 lines
9.0 KiB
C#
using System;
|
|
using System.Data;
|
|
using System.Data.Common;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Xunit;
|
|
|
|
namespace Dapper.Tests
|
|
{
|
|
/// <summary>
|
|
/// If Docker Desktop is installed, run the following command to start a container suitable for the tests.
|
|
/// <code>
|
|
/// docker run -d -p 3306:3306 --name Dapper.Tests.MySQL -e MYSQL_DATABASE=tests -e MYSQL_USER=test -e MYSQL_PASSWORD=pass -e MYSQL_ROOT_PASSWORD=pass mysql
|
|
/// </code>
|
|
/// </summary>
|
|
public sealed class MySqlProvider : DatabaseProvider
|
|
{
|
|
public override DbProviderFactory Factory => MySqlConnector.MySqlConnectorFactory.Instance;
|
|
public override string GetConnectionString() =>
|
|
GetConnectionString("MySqlConnectionString", "Server=localhost;Database=tests;Uid=test;Pwd=pass;");
|
|
|
|
public DbConnection GetMySqlConnection(bool open = true,
|
|
bool convertZeroDatetime = false, bool allowZeroDatetime = false)
|
|
{
|
|
string cs = GetConnectionString();
|
|
var csb = Factory.CreateConnectionStringBuilder()!;
|
|
csb.ConnectionString = cs;
|
|
((dynamic)csb).AllowZeroDateTime = allowZeroDatetime;
|
|
((dynamic)csb).ConvertZeroDateTime = convertZeroDatetime;
|
|
var conn = Factory.CreateConnection()!;
|
|
conn.ConnectionString = csb.ConnectionString;
|
|
if (open) conn.Open();
|
|
return conn;
|
|
}
|
|
}
|
|
public class MySQLTests : TestBase<MySqlProvider>
|
|
{
|
|
[FactMySql]
|
|
public void DapperEnumValue_Mysql()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection();
|
|
Common.DapperEnumValue(conn);
|
|
}
|
|
|
|
[FactMySql]
|
|
public void Issue552_SignedUnsignedBooleans()
|
|
{
|
|
using (var conn = Provider.GetMySqlConnection(true, false, false))
|
|
{
|
|
conn.Execute(@"
|
|
CREATE TEMPORARY TABLE IF NOT EXISTS `bar` (
|
|
`id` INT NOT NULL,
|
|
`bool_val` BOOL NULL,
|
|
PRIMARY KEY (`id`));
|
|
|
|
truncate table bar;
|
|
insert bar (id, bool_val) values (1, null);
|
|
insert bar (id, bool_val) values (2, 0);
|
|
insert bar (id, bool_val) values (3, 1);
|
|
insert bar (id, bool_val) values (4, null);
|
|
insert bar (id, bool_val) values (5, 1);
|
|
insert bar (id, bool_val) values (6, 0);
|
|
insert bar (id, bool_val) values (7, null);
|
|
insert bar (id, bool_val) values (8, 1);");
|
|
|
|
var rows = conn.Query<MySqlHasBool>("select * from bar;").ToDictionary(x => x.Id);
|
|
|
|
Assert.Null(rows[1].Bool_Val);
|
|
Assert.False(rows[2].Bool_Val);
|
|
Assert.True(rows[3].Bool_Val);
|
|
Assert.Null(rows[4].Bool_Val);
|
|
Assert.True(rows[5].Bool_Val);
|
|
Assert.False(rows[6].Bool_Val);
|
|
Assert.Null(rows[7].Bool_Val);
|
|
Assert.True(rows[8].Bool_Val);
|
|
}
|
|
}
|
|
|
|
private class MySqlHasBool
|
|
{
|
|
public int Id { get; set; }
|
|
public bool? Bool_Val { get; set; }
|
|
}
|
|
|
|
[FactMySql]
|
|
public void Issue295_NullableDateTime_MySql_Default()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection(true, false, false);
|
|
Common.TestDateTime(conn);
|
|
}
|
|
|
|
[FactMySql]
|
|
public void Issue295_NullableDateTime_MySql_ConvertZeroDatetime()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection(true, true, false);
|
|
Common.TestDateTime(conn);
|
|
}
|
|
|
|
[FactMySql(Skip = "See https://github.com/DapperLib/Dapper/issues/295, AllowZeroDateTime=True is not supported")]
|
|
public void Issue295_NullableDateTime_MySql_AllowZeroDatetime()
|
|
{
|
|
using (var conn = Provider.GetMySqlConnection(true, false, true))
|
|
{
|
|
Common.TestDateTime(conn);
|
|
}
|
|
}
|
|
|
|
[FactMySql(Skip = "See https://github.com/DapperLib/Dapper/issues/295, AllowZeroDateTime=True is not supported")]
|
|
public void Issue295_NullableDateTime_MySql_ConvertAllowZeroDatetime()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection(true, true, true);
|
|
Common.TestDateTime(conn);
|
|
}
|
|
|
|
[FactMySql]
|
|
public void Issue426_SO34439033_DateTimeGainsTicks()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection(true, true, true);
|
|
|
|
try { conn.Execute("drop table Issue426_Test"); } catch { /* don't care */ }
|
|
try { conn.Execute("create table Issue426_Test (Id int not null, Time time not null)"); } catch { /* don't care */ }
|
|
const long ticks = 553440000000;
|
|
const int Id = 426;
|
|
|
|
var localObj = new Issue426_Test
|
|
{
|
|
Id = Id,
|
|
Time = TimeSpan.FromTicks(ticks) // from code example
|
|
};
|
|
conn.Execute("replace into Issue426_Test values (@Id,@Time)", localObj);
|
|
|
|
var dbObj = conn.Query<Issue426_Test>("select * from Issue426_Test where Id = @id", new { id = Id }).Single();
|
|
Assert.Equal(Id, dbObj.Id);
|
|
Assert.Equal(ticks, dbObj.Time?.Ticks);
|
|
}
|
|
|
|
[FactMySql]
|
|
public void SO36303462_Tinyint_Bools()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection(true, true, true);
|
|
|
|
try { conn.Execute("drop table SO36303462_Test"); } catch { /* don't care */ }
|
|
conn.Execute("create table SO36303462_Test (Id int not null, IsBold tinyint not null);");
|
|
conn.Execute("insert SO36303462_Test (Id, IsBold) values (1,1);");
|
|
conn.Execute("insert SO36303462_Test (Id, IsBold) values (2,0);");
|
|
conn.Execute("insert SO36303462_Test (Id, IsBold) values (3,1);");
|
|
|
|
var rows = conn.Query<SO36303462>("select * from SO36303462_Test").ToDictionary(x => x.Id);
|
|
Assert.Equal(3, rows.Count);
|
|
Assert.True(rows[1].IsBold);
|
|
Assert.False(rows[2].IsBold);
|
|
Assert.True(rows[3].IsBold);
|
|
}
|
|
|
|
[FactMySql]
|
|
public void Issue1277_ReaderSync()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection();
|
|
|
|
try { conn.Execute("drop table Issue1277_Test"); } catch { /* don't care */ }
|
|
conn.Execute("create table Issue1277_Test (Id int not null, IsBold tinyint not null);");
|
|
conn.Execute("insert Issue1277_Test (Id, IsBold) values (1,1);");
|
|
conn.Execute("insert Issue1277_Test (Id, IsBold) values (2,0);");
|
|
conn.Execute("insert Issue1277_Test (Id, IsBold) values (3,1);");
|
|
|
|
using (var reader = conn.ExecuteReader(
|
|
"select * from Issue1277_Test where Id < @id",
|
|
new { id = 42 }))
|
|
{
|
|
var table = new DataTable();
|
|
table.Load(reader);
|
|
Assert.Equal(2, table.Columns.Count);
|
|
Assert.Equal(3, table.Rows.Count);
|
|
}
|
|
}
|
|
|
|
[FactMySql]
|
|
public async Task Issue1277_ReaderAsync()
|
|
{
|
|
using var conn = Provider.GetMySqlConnection();
|
|
|
|
try { await conn.ExecuteAsync("drop table Issue1277_Test"); } catch { /* don't care */ }
|
|
await conn.ExecuteAsync("create table Issue1277_Test (Id int not null, IsBold tinyint not null);");
|
|
await conn.ExecuteAsync("insert Issue1277_Test (Id, IsBold) values (1,1);");
|
|
await conn.ExecuteAsync("insert Issue1277_Test (Id, IsBold) values (2,0);");
|
|
await conn.ExecuteAsync("insert Issue1277_Test (Id, IsBold) values (3,1);");
|
|
|
|
using (var reader = await conn.ExecuteReaderAsync(
|
|
"select * from Issue1277_Test where Id < @id",
|
|
new { id = 42 }))
|
|
{
|
|
var table = new DataTable();
|
|
table.Load(reader);
|
|
Assert.Equal(2, table.Columns.Count);
|
|
Assert.Equal(3, table.Rows.Count);
|
|
}
|
|
}
|
|
|
|
private class SO36303462
|
|
{
|
|
public int Id { get; set; }
|
|
public bool IsBold { get; set; }
|
|
}
|
|
|
|
public class Issue426_Test
|
|
{
|
|
public long Id { get; set; }
|
|
public TimeSpan? Time { get; set; }
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
|
public class FactMySqlAttribute : FactAttribute
|
|
{
|
|
public override string? Skip
|
|
{
|
|
get { return unavailable ?? base.Skip; }
|
|
set { base.Skip = value; }
|
|
}
|
|
|
|
private static readonly string? unavailable;
|
|
|
|
static FactMySqlAttribute()
|
|
{
|
|
try
|
|
{
|
|
using (DatabaseProvider<MySqlProvider>.Instance.GetMySqlConnection(true)) { /* just trying to see if it works */ }
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
unavailable = $"MySql is unavailable: {ex.Message}";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|