From f7ce4dc63612482ee984589aba9edbea005809c1 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 21 Aug 2020 19:46:23 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20=E4=BA=BA=E5=A4=A7?= =?UTF-8?q?=E9=87=91=E4=BB=93=20Ado.Net=20=E5=AE=9E=E7=8E=B0=20FreeSql.Pro?= =?UTF-8?q?vider.KingbaseES=20#325=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Extensions/FreeSql.Generator/ConsoleApp.cs | 2 +- .../FreeSql.Generator.csproj | 2 +- Extensions/FreeSql.Generator/RazorModel.cs | 3 +- FreeSql.DbContext/DbSet/DbSet.cs | 1 + FreeSql.DbContext/DbSet/DbSetAsync.cs | 2 + FreeSql.DbContext/DbSet/DbSetSync.cs | 2 + FreeSql.DbContext/FreeSql.DbContext.xml | 16 + .../FreeSql.Tests/FreeSql.Tests.csproj | 16 +- .../KingbaseES/Curd/KingbaseESDeleteTest.cs | 106 + ...aseESInsertOrUpdateIfExistsDoNotingTest.cs | 266 +++ .../Curd/KingbaseESInsertOrUpdateTest.cs | 205 ++ .../KingbaseES/Curd/KingbaseESInsertTest.cs | 141 ++ .../KingbaseES/Curd/KingbaseESSelectTest.cs | 1816 +++++++++++++++++ .../KingbaseES/Curd/KingbaseESUpdateTest.cs | 190 ++ .../KingbaseES/Curd/OnConflictDoUpdateTest.cs | 158 ++ .../KingbaseESAdo/KingbaseESAdoTest.cs | 66 + .../KingbaseES/KingbaseESAopTest.cs | 40 + .../KingbaseES/KingbaseESCodeFirstTest.cs | 334 +++ .../KingbaseES/KingbaseESDbFirstTest.cs | 64 + .../KingbaseESExpression/ConvertTest.cs | 169 ++ .../KingbaseESExpression/DateTimeTest.cs | 732 +++++++ .../KingbaseESExpression/MathTest.cs | 156 ++ .../KingbaseESExpression/OtherTest.cs | 165 ++ .../KingbaseESExpression/StringTest.cs | 816 ++++++++ .../KingbaseESExpression/TimeSpanTest.cs | 293 +++ .../KingbaseES/MapType/BoolNullableTest.cs | 1571 ++++++++++++++ .../KingbaseES/MapType/BoolTest.cs | 1105 ++++++++++ .../KingbaseES/MapType/DateTimeOffSetTest.cs | 54 + .../KingbaseES/MapType/EnumTest.cs | 261 +++ .../KingbaseES/MapType/ToStringTest.cs | 570 ++++++ FreeSql.Tests/FreeSql.Tests/g.cs | 14 + FreeSql.sln | 15 + FreeSql/DataType.cs | 7 +- FreeSql/Extensions/FreeSqlGlobalExtensions.cs | 2 + FreeSql/FreeSql.xml | 156 ++ FreeSql/FreeSqlBuilder.cs | 5 + .../SelectProvider/Select0Provider.cs | 1 + FreeSql/Internal/UtilsExpressionTree.cs | 2 + .../Curd/KingbaseESDelete.cs | 99 + .../Curd/KingbaseESInsert.cs | 216 ++ .../Curd/KingbaseESInsertOrUpdate.cs | 57 + .../Curd/KingbaseESOnConflictDoUpdate.cs | 208 ++ .../Curd/KingbaseESSelect.cs | 174 ++ .../Curd/KingbaseESUpdate.cs | 169 ++ .../FreeSql.Provider.KingbaseES.csproj | 45 + .../KingbaseESAdo/KingbaseESAdo.cs | 78 + .../KingbaseESAdo/KingbaseESConnectionPool.cs | 258 +++ .../KingbaseESCodeFirst.cs | 397 ++++ .../KingbaseESDbFirst.cs | 524 +++++ .../KingbaseESExpression.cs | 622 ++++++ .../KingbaseESExtensions.cs | 12 + .../KingbaseESProvider.cs | 60 + .../KingbaseESUtils.cs | 163 ++ Providers/FreeSql.Provider.KingbaseES/key.snk | Bin 0 -> 596 bytes .../lib/Kdbndp.dll | Bin 0 -> 732672 bytes 55 files changed, 12596 insertions(+), 10 deletions(-) create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESDeleteTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateIfExistsDoNotingTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESSelectTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESUpdateTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/OnConflictDoUpdateTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAdo/KingbaseESAdoTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAopTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESCodeFirstTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESDbFirstTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/ConvertTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/DateTimeTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/MathTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/OtherTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/StringTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/TimeSpanTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolNullableTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/DateTimeOffSetTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/EnumTest.cs create mode 100644 FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/ToStringTest.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESDelete.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsert.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsertOrUpdate.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESOnConflictDoUpdate.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESSelect.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESUpdate.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/FreeSql.Provider.KingbaseES.csproj create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESAdo.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESConnectionPool.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESCodeFirst.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESDbFirst.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESExpression.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESExtensions.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESProvider.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/KingbaseESUtils.cs create mode 100644 Providers/FreeSql.Provider.KingbaseES/key.snk create mode 100644 Providers/FreeSql.Provider.KingbaseES/lib/Kdbndp.dll diff --git a/Extensions/FreeSql.Generator/ConsoleApp.cs b/Extensions/FreeSql.Generator/ConsoleApp.cs index b67febfc..38a4f7fa 100644 --- a/Extensions/FreeSql.Generator/ConsoleApp.cs +++ b/Extensions/FreeSql.Generator/ConsoleApp.cs @@ -183,7 +183,7 @@ new Colorful.Formatter("推荐在实体类目录创建 gen.bat,双击它重新 case "oracle": ArgsDbType = DataType.Oracle; break; case "sqlite": ArgsDbType = DataType.Sqlite; break; case "dameng": ArgsDbType = DataType.Dameng; break; - case "odbckingbasees": ArgsDbType = DataType.OdbcKingbaseES; break; + case "kingbasees": ArgsDbType = DataType.KingbaseES; break; case "shentong": ArgsDbType = DataType.ShenTong; break; default: throw new ArgumentException($"-DB 参数错误,不支持的类型:\"{dbargs[0]}\""); } diff --git a/Extensions/FreeSql.Generator/FreeSql.Generator.csproj b/Extensions/FreeSql.Generator/FreeSql.Generator.csproj index 2e01e114..1841b3b0 100644 --- a/Extensions/FreeSql.Generator/FreeSql.Generator.csproj +++ b/Extensions/FreeSql.Generator/FreeSql.Generator.csproj @@ -35,8 +35,8 @@ + - diff --git a/Extensions/FreeSql.Generator/RazorModel.cs b/Extensions/FreeSql.Generator/RazorModel.cs index 8e1d8ca9..63e2e77f 100644 --- a/Extensions/FreeSql.Generator/RazorModel.cs +++ b/Extensions/FreeSql.Generator/RazorModel.cs @@ -112,6 +112,7 @@ public class RazorModel { break; case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: switch (col.DbTypeTextFull.ToLower()) @@ -220,7 +221,7 @@ public class RazorModel { else if ((cstype == typeof(string) && defval.StartsWith("'") && defval.EndsWith("'::character varying") || cstype == typeof(Guid) && defval.StartsWith("'") && defval.EndsWith("'::uuid") ) && (fsql.Ado.DataType == DataType.PostgreSQL || fsql.Ado.DataType == DataType.OdbcPostgreSQL || - fsql.Ado.DataType == DataType.OdbcKingbaseES || + fsql.Ado.DataType == DataType.KingbaseES || fsql.Ado.DataType == DataType.OdbcKingbaseES || fsql.Ado.DataType == DataType.ShenTong)) { defval = defval.Substring(1, defval.LastIndexOf("'::") - 1).Replace("''", "'"); diff --git a/FreeSql.DbContext/DbSet/DbSet.cs b/FreeSql.DbContext/DbSet/DbSet.cs index 69fedabd..f4aef4f3 100644 --- a/FreeSql.DbContext/DbSet/DbSet.cs +++ b/FreeSql.DbContext/DbSet/DbSet.cs @@ -277,6 +277,7 @@ namespace FreeSql case DataType.OdbcSqlServer: case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: return true; diff --git a/FreeSql.DbContext/DbSet/DbSetAsync.cs b/FreeSql.DbContext/DbSet/DbSetAsync.cs index 0c602322..1c2fa9aa 100644 --- a/FreeSql.DbContext/DbSet/DbSetAsync.cs +++ b/FreeSql.DbContext/DbSet/DbSetAsync.cs @@ -41,6 +41,7 @@ namespace FreeSql case DataType.OdbcSqlServer: case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) @@ -104,6 +105,7 @@ namespace FreeSql case DataType.OdbcSqlServer: case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: await DbContextFlushCommandAsync(); diff --git a/FreeSql.DbContext/DbSet/DbSetSync.cs b/FreeSql.DbContext/DbSet/DbSetSync.cs index dd260438..59e173a3 100644 --- a/FreeSql.DbContext/DbSet/DbSetSync.cs +++ b/FreeSql.DbContext/DbSet/DbSetSync.cs @@ -41,6 +41,7 @@ namespace FreeSql case DataType.OdbcSqlServer: case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: if (_tableIdentitys.Length == 1) @@ -108,6 +109,7 @@ namespace FreeSql case DataType.OdbcSqlServer: case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: DbContextFlushCommand(); diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 5a0c8bd0..743835e4 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -130,6 +130,13 @@ 清空状态数据 + + + 根据 lambda 条件删除数据 + + + + 添加 @@ -525,5 +532,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj b/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj index 0acabc69..e6703320 100644 --- a/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj +++ b/FreeSql.Tests/FreeSql.Tests/FreeSql.Tests.csproj @@ -38,6 +38,7 @@ + @@ -51,12 +52,15 @@ ..\..\Providers\FreeSql.Provider.Dameng\lib\DmProvider\netstandard2.0\DmProvider.dll - - ..\..\Providers\FreeSql.Provider.ShenTong\lib\System.Data.OscarClient.dll - - - ..\..\Providers\FreeSql.Provider.ShenTong\lib\Mono.Security.dll - + + ..\..\Providers\FreeSql.Provider.ShenTong\lib\System.Data.OscarClient.dll + + + ..\..\Providers\FreeSql.Provider.ShenTong\lib\Mono.Security.dll + + + ..\..\Providers\FreeSql.Provider.KingbaseES\lib\Kdbndp.dll + diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESDeleteTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESDeleteTest.cs new file mode 100644 index 00000000..2e5a42e4 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESDeleteTest.cs @@ -0,0 +1,106 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESDeleteTest + { + + IDelete delete => g.kingbaseES.Delete(); //�������� + + [Table(Name = "tb_topic22211")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int? Clicks { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void Dywhere() + { + Assert.Null(g.kingbaseES.Delete().ToSql()); + var sql = g.kingbaseES.Delete(new[] { 1, 2 }).ToSql(); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" IN (1,2))", sql); + + sql = g.kingbaseES.Delete(new Topic { Id = 1, Title = "test" }).ToSql(); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" = 1)", sql); + + sql = g.kingbaseES.Delete(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).ToSql(); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" IN (1,2))", sql); + + sql = g.kingbaseES.Delete(new { id = 1 }).ToSql(); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" = 1)", sql); + + sql = g.kingbaseES.Delete(new[] { new { Id1 = 1, Id2 = 10 }, new { Id1 = 2, Id2 = 20 } }).ToSql(); + Assert.Equal("DELETE FROM \"MULTIPKTOPIC\" WHERE (\"ID1\" = 1 AND \"ID2\" = 10 OR \"ID1\" = 2 AND \"ID2\" = 20)", sql); + } + class MultiPkTopic + { + [Column(IsPrimary = true)] + public int Id1 { get; set; } + [Column(IsPrimary = true)] + public int Id2 { get; set; } + public int Clicks { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void Where() + { + var sql = delete.Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" = 1)", sql); + + sql = delete.Where("id = :id", new { id = 1 }).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (id = :id)", sql); + + var item = new Topic { Id = 1, Title = "newtitle" }; + sql = delete.Where(item).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" = 1)", sql); + + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + sql = delete.Where(items).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM \"TB_TOPIC22211\" WHERE (\"ID\" IN (1,2,3,4,5,6,7,8,9,10))", sql); + } + [Fact] + public void ExecuteAffrows() + { + + var id = g.kingbaseES.Insert(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteIdentity(); + Assert.Equal(1, delete.Where(a => a.Id == id).ExecuteAffrows()); + } + [Fact] + public void ExecuteDeleted() + { + + //var item = g.kingbaseES.Insert(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteInserted(); + //Assert.Equal(item[0].Id, delete.Where(a => a.Id == item[0].Id).ExecuteDeleted()[0].Id); + } + + [Fact] + public void AsTable() + { + Assert.Null(g.kingbaseES.Delete().ToSql()); + var sql = g.kingbaseES.Delete(new[] { 1, 2 }).AsTable(a => "TopicAsTable").ToSql(); + Assert.Equal("DELETE FROM \"TOPICASTABLE\" WHERE (\"ID\" IN (1,2))", sql); + + sql = g.kingbaseES.Delete(new Topic { Id = 1, Title = "test" }).AsTable(a => "TopicAsTable").ToSql(); + Assert.Equal("DELETE FROM \"TOPICASTABLE\" WHERE (\"ID\" = 1)", sql); + + sql = g.kingbaseES.Delete(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).AsTable(a => "TopicAsTable").ToSql(); + Assert.Equal("DELETE FROM \"TOPICASTABLE\" WHERE (\"ID\" IN (1,2))", sql); + + sql = g.kingbaseES.Delete(new { id = 1 }).AsTable(a => "TopicAsTable").ToSql(); + Assert.Equal("DELETE FROM \"TOPICASTABLE\" WHERE (\"ID\" = 1)", sql); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateIfExistsDoNotingTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateIfExistsDoNotingTest.cs new file mode 100644 index 00000000..7f8756fd --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateIfExistsDoNotingTest.cs @@ -0,0 +1,266 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESInsertOrUpdateIfExistsDoNotingTest + { + IFreeSql fsql => g.kingbaseES; + + [Fact] + public void InsertOrUpdate_OnlyPrimary() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb01 { id = 1 }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB01""(""ID"") VALUES(1) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb01 { id = 1 }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB01""(""ID"") VALUES(1) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb01 { id = 2 }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB01""(""ID"") VALUES(2) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb01 { id = 1 }, new tbioudb01 { id = 2 }, new tbioudb01 { id = 3 }, new tbioudb01 { id = 4 } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB01""(""ID"") VALUES(1), (2), (3), (4) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(2, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb01 { id = 1 }, new tbioudb01 { id = 2 }, new tbioudb01 { id = 3 }, new tbioudb01 { id = 4 } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB01""(""ID"") VALUES(1), (2), (3), (4) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + } + class tbioudb01 + { + public int id { get; set; } + } + + [Fact] + public void InsertOrUpdate_OnePrimary() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb02 { id = 1, name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB02""(""ID"", ""NAME"") VALUES(1, '01') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb02 { id = 1, name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB02""(""ID"", ""NAME"") VALUES(1, '011') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb02 { id = 2, name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB02""(""ID"", ""NAME"") VALUES(2, '02') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb02 { id = 1, name = "01" }, new tbioudb02 { id = 2, name = "02" }, new tbioudb02 { id = 3, name = "03" }, new tbioudb02 { id = 4, name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB02""(""ID"", ""NAME"") VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(2, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb02 { id = 1, name = "001" }, new tbioudb02 { id = 2, name = "002" }, new tbioudb02 { id = 3, name = "003" }, new tbioudb02 { id = 4, name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB02""(""ID"", ""NAME"") VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList(); + Assert.Equal(4, lst.Where(a => a.name == "0" + a.id).Count()); + } + class tbioudb02 + { + public int id { get; set; } + public string name { get; set; } + } + [Fact] + public void InsertOrUpdate_OnePrimaryAndIdentity() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb022 { id = 1, name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""ID"", ""NAME"") VALUES(1, '01') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb022 { id = 1, name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""ID"", ""NAME"") VALUES(1, '011') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb022 { id = 2, name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""ID"", ""NAME"") VALUES(2, '02') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb022 { id = 1, name = "01" }, new tbioudb022 { id = 2, name = "02" }, new tbioudb022 { id = 3, name = "03" }, new tbioudb022 { id = 4, name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""ID"", ""NAME"") VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(2, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb022 { id = 1, name = "001" }, new tbioudb022 { id = 2, name = "002" }, new tbioudb022 { id = 3, name = "003" }, new tbioudb022 { id = 4, name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""ID"", ""NAME"") VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004') +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList(); + Assert.Equal(4, lst.Where(a => a.name == "0" + a.id).Count()); + + //--no primary + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb022 { name = "01" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""NAME"") VALUES('01')", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb022 { name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""NAME"") VALUES('011')", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb022 { name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""NAME"") VALUES('02')", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb022 { name = "01" }, new tbioudb022 { name = "02" }, new tbioudb022 { name = "03" }, new tbioudb022 { name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""NAME"") VALUES('01'), ('02'), ('03'), ('04')", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb022 { name = "001" }, new tbioudb022 { name = "002" }, new tbioudb022 { name = "003" }, new tbioudb022 { name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""NAME"") VALUES('001'), ('002'), ('003'), ('004')", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + + //--no primary and yes + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb022 { id = 1, name = "100001" }, new tbioudb022 { name = "00001" }, new tbioudb022 { id = 2, name = "100002" }, new tbioudb022 { name = "00002" }, new tbioudb022 { id = 3, name = "100003" }, new tbioudb022 { name = "00003" }, new tbioudb022 { id = 4, name = "100004" }, new tbioudb022 { name = "00004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB022""(""ID"", ""NAME"") VALUES(1, '100001'), (2, '100002'), (3, '100003'), (4, '100004') +ON CONFLICT(""ID"") DO NOTHING + +; + +INSERT INTO ""TBIOUDB022""(""NAME"") VALUES('00001'), ('00002'), ('00003'), ('00004')", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + lst = fsql.Select().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList(); + Assert.Equal(4, lst.Where(a => a.name == "0" + a.id).Count()); + } + class tbioudb022 + { + [Column(IsIdentity = true)] + public int id { get; set; } + public string name { get; set; } + } + + [Fact] + public void InsertOrUpdate_TwoPrimary() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb03 { id1 = 1, id2 = "01", name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '01') +ON CONFLICT(""ID1"", ""ID2"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb03 { id1 = 1, id2 = "01", name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '011') +ON CONFLICT(""ID1"", ""ID2"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb03 { id1 = 2, id2 = "02", name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB03""(""ID1"", ""ID2"", ""NAME"") VALUES(2, '02', '02') +ON CONFLICT(""ID1"", ""ID2"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb03 { id1 = 1, id2 = "01", name = "01" }, new tbioudb03 { id1 = 2, id2 = "02", name = "02" }, new tbioudb03 { id1 = 3, id2 = "03", name = "03" }, new tbioudb03 { id1 = 4, id2 = "04", name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04') +ON CONFLICT(""ID1"", ""ID2"") DO NOTHING", sql); + Assert.Equal(2, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb03 { id1 = 1, id2 = "01", name = "001" }, new tbioudb03 { id1 = 2, id2 = "02", name = "002" }, new tbioudb03 { id1 = 3, id2 = "03", name = "003" }, new tbioudb03 { id1 = 4, id2 = "04", name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004') +ON CONFLICT(""ID1"", ""ID2"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList(); + Assert.Equal(4, lst.Where(a => a.name == "0" + a.id1).Count()); + } + class tbioudb03 + { + [Column(IsPrimary = true)] + public int id1 { get; set; } + [Column(IsPrimary = true)] + public string id2 { get; set; } + public string name { get; set; } + } + + [Fact] + public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb04 { id = 1, name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '01', 0, current_timestamp) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb04 { id = 1, name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '011', 0, current_timestamp) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new tbioudb04 { id = 2, name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(2, '02', 0, current_timestamp) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb04 { id = 1, name = "01" }, new tbioudb04 { id = 2, name = "02" }, new tbioudb04 { id = 3, name = "03" }, new tbioudb04 { id = 4, name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '01', 0, current_timestamp), (2, '02', 0, current_timestamp), (3, '03', 0, current_timestamp), (4, '04', 0, current_timestamp) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(2, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().IfExistsDoNothing().SetSource(new[] { new tbioudb04 { id = 1, name = "001" }, new tbioudb04 { id = 2, name = "002" }, new tbioudb04 { id = 3, name = "003" }, new tbioudb04 { id = 4, name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOUDB04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '001', 0, current_timestamp), (2, '002', 0, current_timestamp), (3, '003', 0, current_timestamp), (4, '004', 0, current_timestamp) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList(); + Assert.Equal(4, lst.Where(a => a.name == "0" + a.id).Count()); + } + class tbioudb04 + { + public int id { get; set; } + public string name { get; set; } + [Column(IsVersion = true)] + public int version { get; set; } + [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)] + public DateTime CreateTime { get; set; } + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateTest.cs new file mode 100644 index 00000000..7d7c6758 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertOrUpdateTest.cs @@ -0,0 +1,205 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESInsertOrUpdateTest + { + IFreeSql fsql => g.kingbaseES; + + [Fact] + public void InsertOrUpdate_OnlyPrimary() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().SetSource(new tbiou01 { id = 1 }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU01""(""ID"") VALUES(1) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou01 { id = 1 }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU01""(""ID"") VALUES(1) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou01 { id = 2 }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU01""(""ID"") VALUES(2) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU01""(""ID"") VALUES(1), (2), (3), (4) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(2, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou01 { id = 1 }, new tbiou01 { id = 2 }, new tbiou01 { id = 3 }, new tbiou01 { id = 4 } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU01""(""ID"") VALUES(1), (2), (3), (4) +ON CONFLICT(""ID"") DO NOTHING", sql); + Assert.Equal(0, iou.ExecuteAffrows()); + } + class tbiou01 + { + public int id { get; set; } + } + + [Fact] + public void InsertOrUpdate_OnePrimary() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().SetSource(new tbiou02 { id = 1, name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU02""(""ID"", ""NAME"") VALUES(1, '01') +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou02 { id = 1, name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU02""(""ID"", ""NAME"") VALUES(1, '011') +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou02 { id = 2, name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU02""(""ID"", ""NAME"") VALUES(2, '02') +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou02 { id = 1, name = "01" }, new tbiou02 { id = 2, name = "02" }, new tbiou02 { id = 3, name = "03" }, new tbiou02 { id = 4, name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU02""(""ID"", ""NAME"") VALUES(1, '01'), (2, '02'), (3, '03'), (4, '04') +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou02 { id = 1, name = "001" }, new tbiou02 { id = 2, name = "002" }, new tbiou02 { id = 3, name = "003" }, new tbiou02 { id = 4, name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU02""(""ID"", ""NAME"") VALUES(1, '001'), (2, '002'), (3, '003'), (4, '004') +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList(); + Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count()); + } + class tbiou02 + { + public int id { get; set; } + public string name { get; set; } + } + + [Fact] + public void InsertOrUpdate_TwoPrimary() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '01') +ON CONFLICT(""ID1"", ""ID2"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou03 { id1 = 1, id2 = "01", name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '011') +ON CONFLICT(""ID1"", ""ID2"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou03 { id1 = 2, id2 = "02", name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU03""(""ID1"", ""ID2"", ""NAME"") VALUES(2, '02', '02') +ON CONFLICT(""ID1"", ""ID2"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "01" }, new tbiou03 { id1 = 2, id2 = "02", name = "02" }, new tbiou03 { id1 = 3, id2 = "03", name = "03" }, new tbiou03 { id1 = 4, id2 = "04", name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '01'), (2, '02', '02'), (3, '03', '03'), (4, '04', '04') +ON CONFLICT(""ID1"", ""ID2"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou03 { id1 = 1, id2 = "01", name = "001" }, new tbiou03 { id1 = 2, id2 = "02", name = "002" }, new tbiou03 { id1 = 3, id2 = "03", name = "003" }, new tbiou03 { id1 = 4, id2 = "04", name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU03""(""ID1"", ""ID2"", ""NAME"") VALUES(1, '01', '001'), (2, '02', '002'), (3, '03', '003'), (4, '04', '004') +ON CONFLICT(""ID1"", ""ID2"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME""", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => a.id1 == 1 && a.id2 == "01" || a.id1 == 2 && a.id2 == "02" || a.id1 == 3 && a.id2 == "03" || a.id1 == 4 && a.id2 == "04").ToList(); + Assert.Equal(4, lst.Where(a => a.name == "00" + a.id1).Count()); + } + class tbiou03 + { + [Column(IsPrimary = true)] + public int id1 { get; set; } + [Column(IsPrimary = true)] + public string id2 { get; set; } + public string name { get; set; } + } + + [Fact] + public void InsertOrUpdate_OnePrimaryAndVersionAndCanUpdate() + { + fsql.Delete().Where("1=1").ExecuteAffrows(); + var iou = fsql.InsertOrUpdate().SetSource(new tbiou04 { id = 1, name = "01" }); + var sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '01', 0, current_timestamp) +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME"", +""VERSION"" = ""TBIOU04"".""VERSION"" + 1", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou04 { id = 1, name = "011" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '011', 0, current_timestamp) +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME"", +""VERSION"" = ""TBIOU04"".""VERSION"" + 1", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new tbiou04 { id = 2, name = "02" }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(2, '02', 0, current_timestamp) +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME"", +""VERSION"" = ""TBIOU04"".""VERSION"" + 1", sql); + Assert.Equal(1, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou04 { id = 1, name = "01" }, new tbiou04 { id = 2, name = "02" }, new tbiou04 { id = 3, name = "03" }, new tbiou04 { id = 4, name = "04" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '01', 0, current_timestamp), (2, '02', 0, current_timestamp), (3, '03', 0, current_timestamp), (4, '04', 0, current_timestamp) +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME"", +""VERSION"" = ""TBIOU04"".""VERSION"" + 1", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + + iou = fsql.InsertOrUpdate().SetSource(new[] { new tbiou04 { id = 1, name = "001" }, new tbiou04 { id = 2, name = "002" }, new tbiou04 { id = 3, name = "003" }, new tbiou04 { id = 4, name = "004" } }); + sql = iou.ToSql(); + Assert.Equal(@"INSERT INTO ""TBIOU04""(""ID"", ""NAME"", ""VERSION"", ""CREATETIME"") VALUES(1, '001', 0, current_timestamp), (2, '002', 0, current_timestamp), (3, '003', 0, current_timestamp), (4, '004', 0, current_timestamp) +ON CONFLICT(""ID"") DO UPDATE SET +""NAME"" = EXCLUDED.""NAME"", +""VERSION"" = ""TBIOU04"".""VERSION"" + 1", sql); + Assert.Equal(4, iou.ExecuteAffrows()); + var lst = fsql.Select().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList(); + Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count()); + } + class tbiou04 + { + public int id { get; set; } + public string name { get; set; } + [Column(IsVersion = true)] + public int version { get; set; } + [Column(CanUpdate = false, ServerTime = DateTimeKind.Local)] + public DateTime CreateTime { get; set; } + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertTest.cs new file mode 100644 index 00000000..bf4411ca --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESInsertTest.cs @@ -0,0 +1,141 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESInsertTest + { + + IInsert insert => g.kingbaseES.Insert(); + + [Table(Name = "tb_topic_insert")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void AppendData() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + var sql = insert.AppendData(items.First()).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(0, 'newtitle0', '0001-01-01 00:00:00.000000')", sql); + + sql = insert.AppendData(items).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(0, 'newtitle0', '0001-01-01 00:00:00.000000'), (100, 'newtitle1', '0001-01-01 00:00:00.000000'), (200, 'newtitle2', '0001-01-01 00:00:00.000000'), (300, 'newtitle3', '0001-01-01 00:00:00.000000'), (400, 'newtitle4', '0001-01-01 00:00:00.000000'), (500, 'newtitle5', '0001-01-01 00:00:00.000000'), (600, 'newtitle6', '0001-01-01 00:00:00.000000'), (700, 'newtitle7', '0001-01-01 00:00:00.000000'), (800, 'newtitle8', '0001-01-01 00:00:00.000000'), (900, 'newtitle9', '0001-01-01 00:00:00.000000')", sql); + + sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"TITLE\") VALUES('newtitle0'), ('newtitle1'), ('newtitle2'), ('newtitle3'), ('newtitle4'), ('newtitle5'), ('newtitle6'), ('newtitle7'), ('newtitle8'), ('newtitle9')", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\") VALUES(0, 'newtitle0'), (100, 'newtitle1'), (200, 'newtitle2'), (300, 'newtitle3'), (400, 'newtitle4'), (500, 'newtitle5'), (600, 'newtitle6'), (700, 'newtitle7'), (800, 'newtitle8'), (900, 'newtitle9')", sql); + } + + [Fact] + public void InsertColumns() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"TITLE\") VALUES('newtitle0'), ('newtitle1'), ('newtitle2'), ('newtitle3'), ('newtitle4'), ('newtitle5'), ('newtitle6'), ('newtitle7'), ('newtitle8'), ('newtitle9')", sql); + + sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\") VALUES(0, 'newtitle0'), (100, 'newtitle1'), (200, 'newtitle2'), (300, 'newtitle3'), (400, 'newtitle4'), (500, 'newtitle5'), (600, 'newtitle6'), (700, 'newtitle7'), (800, 'newtitle8'), (900, 'newtitle9')", sql); + } + [Fact] + public void IgnoreColumns() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\", \"TITLE\") VALUES(0, 'newtitle0'), (100, 'newtitle1'), (200, 'newtitle2'), (300, 'newtitle3'), (400, 'newtitle4'), (500, 'newtitle5'), (600, 'newtitle6'), (700, 'newtitle7'), (800, 'newtitle8'), (900, 'newtitle9')", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql(); + Assert.Equal("INSERT INTO \"TB_TOPIC_INSERT\"(\"CLICKS\") VALUES(0), (100), (200), (300), (400), (500), (600), (700), (800), (900)", sql); + + g.kingbaseES.Delete().Where("1=1").ExecuteAffrows(); + var itemsIgnore = new List(); + for (var a = 0; a < 2072; a++) itemsIgnore.Add(new TopicIgnore { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + g.kingbaseES.Insert().AppendData(itemsIgnore).IgnoreColumns(a => new { a.Title }).ExecuteAffrows(); + Assert.Equal(2072, itemsIgnore.Count); + Assert.Equal(2072, g.kingbaseES.Select().Where(a => a.Title == null).Count()); + } + [Table(Name = "tb_topicIgnoreColumns")] + class TopicIgnore + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + [Fact] + public void ExecuteAffrows() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + Assert.Equal(1, insert.AppendData(items.First()).ExecuteAffrows()); + Assert.Equal(10, insert.AppendData(items).ExecuteAffrows()); + } + [Fact] + public void ExecuteIdentity() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + Assert.NotEqual(0, insert.AppendData(items.First()).ExecuteIdentity()); + } + [Fact] + public void ExecuteInserted() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + insert.AppendData(items.First()).ExecuteInserted(); + } + + [Fact] + public void AsTable() + { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newTitle{a}", Clicks = a * 100 }); + + var sql = insert.AppendData(items.First()).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(0, 'newTitle0', '0001-01-01 00:00:00.000000')", sql); + + sql = insert.AppendData(items).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"CLICKS\", \"TITLE\", \"CREATETIME\") VALUES(0, 'newTitle0', '0001-01-01 00:00:00.000000'), (100, 'newTitle1', '0001-01-01 00:00:00.000000'), (200, 'newTitle2', '0001-01-01 00:00:00.000000'), (300, 'newTitle3', '0001-01-01 00:00:00.000000'), (400, 'newTitle4', '0001-01-01 00:00:00.000000'), (500, 'newTitle5', '0001-01-01 00:00:00.000000'), (600, 'newTitle6', '0001-01-01 00:00:00.000000'), (700, 'newTitle7', '0001-01-01 00:00:00.000000'), (800, 'newTitle8', '0001-01-01 00:00:00.000000'), (900, 'newTitle9', '0001-01-01 00:00:00.000000')", sql); + + sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"TITLE\") VALUES('newTitle0'), ('newTitle1'), ('newTitle2'), ('newTitle3'), ('newTitle4'), ('newTitle5'), ('newTitle6'), ('newTitle7'), ('newTitle8'), ('newTitle9')", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"CLICKS\", \"TITLE\") VALUES(0, 'newTitle0'), (100, 'newTitle1'), (200, 'newTitle2'), (300, 'newTitle3'), (400, 'newTitle4'), (500, 'newTitle5'), (600, 'newTitle6'), (700, 'newTitle7'), (800, 'newTitle8'), (900, 'newTitle9')", sql); + + sql = insert.AppendData(items).InsertColumns(a => a.Title).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"TITLE\") VALUES('newTitle0'), ('newTitle1'), ('newTitle2'), ('newTitle3'), ('newTitle4'), ('newTitle5'), ('newTitle6'), ('newTitle7'), ('newTitle8'), ('newTitle9')", sql); + + sql = insert.AppendData(items).InsertColumns(a => new { a.Title, a.Clicks }).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"CLICKS\", \"TITLE\") VALUES(0, 'newTitle0'), (100, 'newTitle1'), (200, 'newTitle2'), (300, 'newTitle3'), (400, 'newTitle4'), (500, 'newTitle5'), (600, 'newTitle6'), (700, 'newTitle7'), (800, 'newTitle8'), (900, 'newTitle9')", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"CLICKS\", \"TITLE\") VALUES(0, 'newTitle0'), (100, 'newTitle1'), (200, 'newTitle2'), (300, 'newTitle3'), (400, 'newTitle4'), (500, 'newTitle5'), (600, 'newTitle6'), (700, 'newTitle7'), (800, 'newTitle8'), (900, 'newTitle9')", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).AsTable(a => "Topic_InsertAsTable").ToSql(); + Assert.Equal("INSERT INTO \"TOPIC_INSERTASTABLE\"(\"CLICKS\") VALUES(0), (100), (200), (300), (400), (500), (600), (700), (800), (900)", sql); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESSelectTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESSelectTest.cs new file mode 100644 index 00000000..14a9788a --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESSelectTest.cs @@ -0,0 +1,1816 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESSelectTest + { + + ISelect select => g.kingbaseES.Select(); + + [Table(Name = "tb_topic22")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo + { + [Column(IsIdentity = true)] + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo + { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + + class TopicInserts + { + public Guid Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + public partial class Song + { + [Column(IsIdentity = true)] + public int Id { get; set; } + public DateTime? Create_time { get; set; } + public bool? Is_deleted { get; set; } + public string Title { get; set; } + public string Url { get; set; } + + public virtual ICollection Tags { get; set; } + } + public partial class Song_tag + { + public int Song_id { get; set; } + public virtual Song Song { get; set; } + + public int Tag_id { get; set; } + public virtual Tag Tag { get; set; } + } + public partial class Tag + { + [Column(IsIdentity = true)] + public int Id { get; set; } + public int? Parent_id { get; set; } + public virtual Tag Parent { get; set; } + + public decimal? Ddd { get; set; } + public string Name { get; set; } + + public virtual ICollection Songs { get; set; } + public virtual ICollection Tags { get; set; } + } + + [Fact] + public void AsSelect() + { + //OneToOne、ManyToOne + var t0 = g.kingbaseES.Select().Where(a => a.Parent.Parent.Name == "粤语").ToSql(); + //SELECT a.`Id`, a.`Parent_id`, a__Parent.`Id` as3, a__Parent.`Parent_id` as4, a__Parent.`Ddd`, a__Parent.`Name`, a.`Ddd` as7, a.`Name` as8 + //FROM `Tag` a + //LEFT JOIN `Tag` a__Parent ON a__Parent.`Id` = a.`Parent_id` + //LEFT JOIN `Tag` a__Parent__Parent ON a__Parent__Parent.`Id` = a__Parent.`Parent_id` + //WHERE (a__Parent__Parent.`Name` = '粤语') + + //OneToMany + var t1 = g.kingbaseES.Select().Where(a => a.Tags.AsSelect().Any(t => t.Parent.Id == 10)).ToSql(); + //SELECT a.`Id`, a.`Parent_id`, a.`Ddd`, a.`Name` + //FROM `Tag` a + //WHERE (exists(SELECT 1 + // FROM `Tag` t + // LEFT JOIN `Tag` t__Parent ON t__Parent.`Id` = t.`Parent_id` + // WHERE (t__Parent.`Id` = 10) AND (t.`Parent_id` = a.`Id`) + // limit 0,1)) + + //ManyToMany + var t2 = g.kingbaseES.Select().Where(s => s.Tags.AsSelect().Any(t => t.Name == "国语")).ToSql(); + //SELECT a.`Id`, a.`Create_time`, a.`Is_deleted`, a.`Title`, a.`Url` + //FROM `Song` a + //WHERE(exists(SELECT 1 + // FROM `Song_tag` Mt_Ms + // WHERE(Mt_Ms.`Song_id` = a.`Id`) AND(exists(SELECT 1 + // FROM `Tag` t + // WHERE(t.`Name` = '国语') AND(t.`Id` = Mt_Ms.`Tag_id`) + // limit 0, 1)) + // limit 0, 1)) + } + + [Fact] + public void Lazy() + { + var tags = g.kingbaseES.Select().Where(a => a.Parent.Name == "xxx") + .LeftJoin(a => a.Parent_id == a.Parent.Id) + .ToSql(); + + var songs = g.kingbaseES.Select().Limit(10).ToList(); + } + + [Fact] + public void ToDataTable() + { + var items = new List(); + for (var a = 0; a < 11; a++) items.Add(new TopicInserts { Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + //Assert.Equal(1, g.kingbaseES.Insert().AppendData(items.First()).ExecuteAffrows()); + Assert.Equal(11, g.kingbaseES.Insert().AppendData(items).ExecuteAffrows()); + + //items = Enumerable.Range(0, 9989).Select(a => new TopicInserts { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList(); + //Assert.Equal(9989, g.kingbaseES.Insert(items).ExecuteAffrows()); + + //var dt1 = select.ToDataTable(); + //var dt2 = select.ToDataTable("id, 111222"); + //var dt3 = select.ToDataTable(a => new { a.Id, a.Type.Name, now = DateTime.Now }); + } + class TestDto + { + public int id { get; set; } + public string name { get; set; } //这是join表的属性 + public int ParentId { get; set; } //这是join表的属性 + } + class TestDto2 + { + public int id { get; set; } + public string name { get; set; } //这是join表的属性 + public int ParentId { get; set; } //这是join表的属性 + + public TestDto2() { } + public TestDto2(int id, string name) + { + this.id = id; + this.name = name; + } + } + [Fact] + public void ToList() + { + + var testDto1 = select.Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto2 = select.Limit(10).ToList(a => new TestDto()); + var testDto3 = select.Limit(10).ToList(a => new TestDto { }); + var testDto4 = select.Limit(10).ToList(a => new TestDto() { }); + + var testDto11 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title }); + var testDto22 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto()); + var testDto33 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto { }); + var testDto44 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto() { }); + + var testDto211 = select.Limit(10).ToList(a => new TestDto2(a.Id, a.Title)); + var testDto212 = select.Limit(10).ToList(a => new TestDto2()); + var testDto213 = select.Limit(10).ToList(a => new TestDto2 { }); + var testDto214 = select.Limit(10).ToList(a => new TestDto2() { }); + var testDto215 = select.Limit(10).ToList(); + + var testDto2211 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto2(a.Id, a.Title)); + var testDto2222 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto2()); + var testDto2233 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto2 { }); + var testDto2244 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(a => new TestDto2() { }); + var testDto2255 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).Limit(10).ToList(); + + g.kingbaseES.Insert().AppendData(new TestGuidIdToList()).ExecuteAffrows(); + var testGuidId5 = g.kingbaseES.Select().ToList(); + var testGuidId6 = g.kingbaseES.Select().ToList(a => a.id); + + var t11 = select.Where(a => a.Type.Name.Length > 0).ToList(true); + var t21 = select.Where(a => a.Type.Parent.Name.Length > 0).ToList(true); + + g.kingbaseES.Delete().Where("1=1").ExecuteAffrows(); + var repo = g.kingbaseES.GetRepository(); + repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; + repo.Insert(new District + { + Code = "001", + Name = "001_name", + Childs = new List(new[] { + new District{ + Code = "001_01", + Name = "001_01_name" + }, + new District{ + Code = "001_02", + Name = "001_02_name" + } + }) + }); + var ddd = g.kingbaseES.Select().LeftJoin(d => d.ParentCode == d.Parent.Code).ToTreeList(); + Assert.Single(ddd); + Assert.Equal(2, ddd[0].Childs.Count); + } + public class District + { + [Column(IsPrimary = true, StringLength = 6)] + public string Code { get; set; } + + [Column(StringLength = 20, IsNullable = false)] + public string Name { get; set; } + + [Column(StringLength = 6)] + public string ParentCode { get; set; } + + [Navigate(nameof(ParentCode))] + public District Parent { get; set; } + + [Navigate(nameof(ParentCode))] + public List Childs { get; set; } + } + [Fact] + public void ToDictionary() + { + g.kingbaseES.Insert(new Topic { Title = "xxx" }).ExecuteAffrows(); + var testDto1 = select.Limit(10).ToDictionary(a => a.Id); + var testDto2 = select.Limit(10).ToDictionary(a => a.Id, a => new { a.Id, a.Title }); + + var repo = g.kingbaseES.GetRepository(); + var dic = repo.Select.Limit(10).ToDictionary(a => a.Id); + var first = dic.First().Value; + first.Clicks++; + repo.Update(first); + } + class TestGuidIdToList + { + public Guid id { get; set; } + public string title { get; set; } = Guid.NewGuid().ToString(); + } + [Fact] + public void ToOne() + { + var testnotfind = select.Where("1=2").First(a => a.CreateTime); + Assert.Equal(default(DateTime), testnotfind); + } + [Fact] + public void ToSql() + { + } + [Fact] + public void Any() + { + var count = select.Where(a => 1 == 1).Count(); + Assert.False(select.Where(a => 1 == 2).Any()); + Assert.Equal(count > 0, select.Where(a => 1 == 1).Any()); + + var sql2222 = select.Where(a => + select.Where(b => b.Id == a.Id && + select.Where(c => c.Id == b.Id).Where(d => d.Id == a.Id).Where(e => e.Id == b.Id) + //.Offset(a.Id) + .Any() + ).Any(c => c.Id == a.Id + 10) + ); + var sql2222Tolist = sql2222.ToList(); + + var collectionSelect = select.Where(a => + a.Type.Guid == a.TypeGuid && + a.Type.Parent.Id == a.Type.ParentId && + a.Type.Parent.Types.AsSelect().Where(b => b.Name == a.Title).Any(b => b.ParentId == a.Type.Parent.Id) + ); + collectionSelect.ToList(); + } + [Fact] + public void Count() + { + var count = select.Where(a => 1 == 1).Count(); + select.Where(a => 1 == 1).Count(out var count2); + Assert.Equal(count, count2); + Assert.Equal(0, select.Where(a => 1 == 2).Count()); + + var subquery = select.ToSql(a => new + { + all = a, + count = select.Where(b => b.Id > 0 && b.Id == a.Id).Count() + }); + var subqueryList = select.ToList(a => new + { + all = a, + count = select.Where(b => b.Id > 0 && b.Id == a.Id).Count() + }); + } + [Fact] + public void Master() + { + Assert.StartsWith(" SELECT", select.Master().Where(a => 1 == 1).ToSql()); + } + [Fact] + public void From() + { + var query2 = select.From((s, b) => s + .LeftJoin(a => a.TypeGuid == b.Guid) + ); + var sql2 = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" b ON a.\"TYPEGUID\" = b.\"GUID\"", sql2); + query2.ToList(); + + var query3 = select.From((s, b, c) => s + .LeftJoin(a => a.TypeGuid == b.Guid) + .LeftJoin(a => b.ParentId == c.Id) + ); + var sql3 = query3.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" b ON a.\"TYPEGUID\" = b.\"GUID\" LEFT JOIN \"TESTTYPEPARENTINFO\" c ON b.\"PARENTID\" = c.\"ID\"", sql3); + query3.ToList(); + } + [Fact] + public void LeftJoin() + { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.LeftJoin(a => a.Type.Guid == a.TypeGuid); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + + query = select.LeftJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx'", sql); + query.ToList(); + + query = select.LeftJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + query.ToList(); + + //���û�е������� + query = select.LeftJoin((a, b) => b.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" b ON b.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + + query = select.LeftJoin((a, b) => b.Guid == a.TypeGuid && b.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" b ON b.\"GUID\" = a.\"TYPEGUID\" AND b.\"NAME\" = 'xxx'", sql); + query.ToList(); + + query = select.LeftJoin((a, a__Type) => a__Type.Guid == a.TypeGuid && a__Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + query.ToList(); + + //������� + query = select + .LeftJoin(a => a.Type.Guid == a.TypeGuid) + .LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\"", sql); + query.ToList(); + + query = select + .LeftJoin((a, a__Type) => a__Type.Guid == a.TypeGuid) + .LeftJoin((a, c) => c.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" LEFT JOIN \"TESTTYPEPARENTINFO\" c ON c.\"ID\" = a__Type.\"PARENTID\"", sql); + query.ToList(); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .LeftJoin(a => a.TypeGuid == b.Guid) + .LeftJoin(a => b.ParentId == c.Id)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" b ON a.\"TYPEGUID\" = b.\"GUID\" LEFT JOIN \"TESTTYPEPARENTINFO\" c ON b.\"PARENTID\" = c.\"ID\"", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.LeftJoin("\"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\""); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + } + [Fact] + public void InnerJoin() + { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.InnerJoin(a => a.Type.Guid == a.TypeGuid); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + + query = select.InnerJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx'", sql); + query.ToList(); + + query = select.InnerJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + query.ToList(); + + //���û�е������� + query = select.InnerJoin((a, b) => b.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" b ON b.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + + query = select.InnerJoin((a, b) => b.Guid == a.TypeGuid && b.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" b ON b.\"GUID\" = a.\"TYPEGUID\" AND b.\"NAME\" = 'xxx'", sql); + query.ToList(); + + query = select.InnerJoin((a, a__Type) => a__Type.Guid == a.TypeGuid && a__Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + query.ToList(); + + //������� + query = select + .InnerJoin(a => a.Type.Guid == a.TypeGuid) + .InnerJoin(a => a.Type.Parent.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" INNER JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\"", sql); + query.ToList(); + + query = select + .InnerJoin((a, a__Type) => a__Type.Guid == a.TypeGuid) + .InnerJoin((a, c) => c.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" INNER JOIN \"TESTTYPEPARENTINFO\" c ON c.\"ID\" = a__Type.\"PARENTID\"", sql); + query.ToList(); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .InnerJoin(a => a.TypeGuid == b.Guid) + .InnerJoin(a => b.ParentId == c.Id)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" b ON a.\"TYPEGUID\" = b.\"GUID\" INNER JOIN \"TESTTYPEPARENTINFO\" c ON b.\"PARENTID\" = c.\"ID\"", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.InnerJoin("\"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\""); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a INNER JOIN \"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + } + [Fact] + public void RightJoin() + { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.RightJoin(a => a.Type.Guid == a.TypeGuid); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + + query = select.RightJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx'", sql); + query.ToList(); + + query = select.RightJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + query.ToList(); + + //���û�е������� + query = select.RightJoin((a, b) => b.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" b ON b.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + + query = select.RightJoin((a, b) => b.Guid == a.TypeGuid && b.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" b ON b.\"GUID\" = a.\"TYPEGUID\" AND b.\"NAME\" = 'xxx'", sql); + query.ToList(); + + query = select.RightJoin((a, a__Type) => a__Type.Guid == a.TypeGuid && a__Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + query.ToList(); + + //������� + query = select + .RightJoin(a => a.Type.Guid == a.TypeGuid) + .RightJoin(a => a.Type.Parent.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" RIGHT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\"", sql); + query.ToList(); + + query = select + .RightJoin((a, a__Type) => a__Type.Guid == a.TypeGuid) + .RightJoin((a, c) => c.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" RIGHT JOIN \"TESTTYPEPARENTINFO\" c ON c.\"ID\" = a__Type.\"PARENTID\"", sql); + query.ToList(); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .RightJoin(a => a.TypeGuid == b.Guid) + .RightJoin(a => b.ParentId == c.Id)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" b ON a.\"TYPEGUID\" = b.\"GUID\" RIGHT JOIN \"TESTTYPEPARENTINFO\" c ON b.\"PARENTID\" = c.\"ID\"", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.RightJoin("\"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\""); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a RIGHT JOIN \"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\"", sql); + query.ToList(); + } + [Fact] + public void Where() + { + var sqltmp1 = select.Where(a => a.Id == 0 && (a.Title == "x" || a.Title == "y") && a.Clicks == 1).ToSql(); + var sqltmp2 = select.Where(a => a.Id.Equals(true) && (a.Title.Equals("x") || a.Title.Equals("y")) && a.Clicks.Equals(1)).ToSql(); + var sqltmp3 = select.Where(a => a.Id == 0).Where(a => ((a.Title == "x" && a.Title == "z") || a.Title == "y")).ToSql(); + + var sqltmp4 = select.Where(a => (a.Id - 10) / 2 > 0).ToSql(); + + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.Where(a => a.Id == 10); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a WHERE (a.\"ID\" = 10)", sql); + query.ToList(); + + query = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a WHERE ((a.\"ID\" = 10 AND a.\"ID\" > 10 OR a.\"CLICKS\" > 100))", sql); + query.ToList(); + + query = select.Where(a => a.Id == 10).Where(a => a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a WHERE (a.\"ID\" = 10) AND (a.\"CLICKS\" > 100)", sql); + query.ToList(); + + query = select.Where(a => a.Type.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" WHERE (a__Type.\"NAME\" = 'typeTitle')", sql); + query.ToList(); + + query = select.Where(a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" WHERE (a__Type.\"NAME\" = 'typeTitle' AND a__Type.\"GUID\" = a.\"TYPEGUID\")", sql); + query.ToList(); + + query = select.Where(a => a.Type.Parent.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"NAME\" = 'tparent')", sql); + query.ToList(); + + //���û�е������ԣ��򵥶������ + query = select.Where((a, b) => b.Guid == a.TypeGuid && b.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a, \"TESTTYPEINFO\" b WHERE (b.\"GUID\" = a.\"TYPEGUID\" AND b.\"NAME\" = 'typeTitle')", sql); + query.ToList(); + + query = select.Where((a, b) => b.Name == "typeTitle" && b.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a, \"TESTTYPEINFO\" b WHERE (b.\"NAME\" = 'typeTitle' AND b.\"GUID\" = a.\"TYPEGUID\")", sql); + query.ToList(); + + query = select.Where((a, b, c) => c.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a, \"TESTTYPEPARENTINFO\" c WHERE (c.\"NAME\" = 'tparent')", sql); + query.ToList(); + + //����һ�� From ��Ķ������ + var query2 = select.From((s, b, c) => s + .Where(a => a.Id == 10 && c.Name == "xxx") + .Where(a => b.ParentId == 20)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a, \"TESTTYPEINFO\" b, \"TESTTYPEPARENTINFO\" c WHERE (a.\"ID\" = 10 AND c.\"NAME\" = 'xxx') AND (b.\"PARENTID\" = 20)", sql); + query2.ToList(); + } + [Fact] + public void WhereIf() + { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.WhereIf(true, a => a.Id == 10); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a WHERE (a.\"ID\" = 10)", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Id == 10 && a.Id > 10 || a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a WHERE ((a.\"ID\" = 10 AND a.\"ID\" > 10 OR a.\"CLICKS\" > 100))", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Id == 10).WhereIf(true, a => a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a WHERE (a.\"ID\" = 10) AND (a.\"CLICKS\" > 100)", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Type.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" WHERE (a__Type.\"NAME\" = 'typeTitle')", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" WHERE (a__Type.\"NAME\" = 'typeTitle' AND a__Type.\"GUID\" = a.\"TYPEGUID\")", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Type.Parent.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a LEFT JOIN \"TESTTYPEINFO\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" LEFT JOIN \"TESTTYPEPARENTINFO\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"NAME\" = 'tparent')", sql); + query.ToList(); + + //����һ�� From ��Ķ������ + var query2 = select.From((s, b, c) => s + .WhereIf(true, a => a.Id == 10 && c.Name == "xxx") + .WhereIf(true, a => b.ParentId == 20)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a, \"TESTTYPEINFO\" b, \"TESTTYPEPARENTINFO\" c WHERE (a.\"ID\" = 10 AND c.\"NAME\" = 'xxx') AND (b.\"PARENTID\" = 20)", sql); + query2.ToList(); + + // ==========================================WhereIf(false) + + //����е�������a.Type��a.Type.Parent ���ǵ������� + query = select.WhereIf(false, a => a.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Id == 10 && a.Id > 10 || a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Id == 10).WhereIf(false, a => a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Type.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TypeGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Type.Parent.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a", sql); + query.ToList(); + + //����һ�� From ��Ķ������ + query2 = select.From((s, b, c) => s + .WhereIf(false, a => a.Id == 10 && c.Name == "xxx") + .WhereIf(false, a => b.ParentId == 20)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a, \"TESTTYPEINFO\" b, \"TESTTYPEPARENTINFO\" c", sql); + query2.ToList(); + } + [Fact] + public void WhereExists() + { + var sql2222 = select.Where(a => select.Where(b => b.Id == a.Id).Any()).ToList(); + + sql2222 = select.Where(a => + select.Where(b => b.Id == a.Id && select.Where(c => c.Id == b.Id).Where(d => d.Id == a.Id).Where(e => e.Id == b.Id) + + //.Offset(a.Id) + + .Any() + ).Any() + ).ToList(); + } + [Fact] + public void GroupBy() + { + var groupby = select.From((s, b, c) => s + .Where(a => a.Id == 1) + ) + .GroupBy((a, b, c) => new { tt2 = a.Title.Substring(0, 2), mod4 = a.Id % 4 }) + .Having(a => a.Count() > 0 && a.Avg(a.Key.mod4) > 0 && a.Max(a.Key.mod4) > 0) + .Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100) + .OrderBy(a => a.Key.tt2) + .OrderByDescending(a => a.Count()) + .Offset(10) + .Limit(2) + .Count(out var trycount) + .ToList(a => new + { + a.Key.tt2, + cou1 = a.Count(), + cou2 = a.Count(a.Value.Item3.Id), + arg1 = a.Avg(a.Key.mod4), + ccc2 = a.Key.tt2 ?? "now()", + //ccc = Convert.ToDateTime("now()"), partby = Convert.ToDecimal("sum(num) over(PARTITION BY server_id,os,rid,chn order by id desc)") + ccc3 = a.Max(a.Value.Item3.Id) + }); + + var testpid1 = g.kingbaseES.Insert().AppendData(new TestTypeInfo { Name = "Name" + DateTime.Now.ToString("yyyyMMddHHmmss") }).ExecuteIdentity(); + g.kingbaseES.Insert().AppendData(new TestInfo { Title = "Title" + DateTime.Now.ToString("yyyyMMddHHmmss"), CreateTime = DateTime.Now, TypeGuid = (int)testpid1 }).ExecuteAffrows(); + + var fkfjfj = select.GroupBy(a => a.Title) + .ToList(a => a.Sum(a.Value.TypeGuid)); + + var aggsql1 = select + .GroupBy(a => a.Title) + .ToSql(b => new + { + b.Key, + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid) + }); + var aggtolist1 = select + .GroupBy(a => a.Title) + .ToList(b => new + { + b.Key, + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid) + }); + var aggtolist11 = select + .GroupBy(a => a.Title) + .ToDictionary(b => new + { + b.Key, + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid) + }); + + var aggsql2 = select + .GroupBy(a => new { a.Title, yyyy = string.Concat(a.CreateTime.Year, '-', a.CreateTime.Month) }) + .ToSql(b => new + { + b.Key.Title, + b.Key.yyyy, + + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid) + }); + var aggtolist2 = select + .GroupBy(a => new { a.Title, yyyy = string.Concat(a.CreateTime.Year, '-', a.CreateTime.Month) }) + .ToList(b => new + { + b.Key.Title, + b.Key.yyyy, + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid) + }); + var aggtolist22 = select + .GroupBy(a => new { a.Title, yyyy = string.Concat(a.CreateTime.Year, '-', a.CreateTime.Month) }) + .ToDictionary(b => new + { + b.Key.Title, + b.Key.yyyy, + b.Key, + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid) + }); + + var aggsql3 = select + .GroupBy(a => a.Title) + .ToSql(b => new + { + b.Key, + cou = b.Count(), + sum2 = b.Sum(b.Value.TypeGuid), + sum3 = b.Sum(b.Value.Type.Parent.Id) + }); + } + [Fact] + public void ToAggregate() + { + var sql = select.ToAggregate(a => new { sum = a.Sum(a.Key.Id + 11.11), avg = a.Avg(a.Key.Id), count = a.Count(), max = a.Max(a.Key.Id), min = a.Min(a.Key.Id) }); + } + [Fact] + public void OrderBy() + { + var sql = select.Offset(10).OrderBy(a => new Random().NextDouble()).ToList(); + } + [Fact] + public void Skip_Offset() + { + var sql = select.Offset(10).ToList(); + } + [Fact] + public void Take_Limit() + { + var sql = select.Limit(10).ToList(); + } + [Fact] + public void Page() + { + var sql1 = select.Page(1, 10).ToList(); + var sql2 = select.Page(2, 10).ToList(); + var sql3 = select.Page(3, 10).ToList(); + + var sql11 = select.OrderBy(a => new Random().NextDouble()).Page(1, 10).ToList(); + var sql22 = select.OrderBy(a => new Random().NextDouble()).Page(2, 10).ToList(); + var sql33 = select.OrderBy(a => new Random().NextDouble()).Page(3, 10).ToList(); + } + [Fact] + public void Distinct() + { + var t1 = select.Distinct().ToList(a => a.Title); + var t2 = select.Distinct().Limit(10).ToList(a => a.Title); + } + + [Fact] + public void Sum() + { + var subquery = select.ToSql(a => new + { + all = a, + count = (long)select.As("b").Sum(b => b.Id) + }); + Assert.Equal(@"SELECT a.""ID"" as1, a.""CLICKS"" as2, a.""TYPEGUID"" as3, a.""TITLE"" as4, a.""CREATETIME"" as5, (SELECT sum(b.""ID"") + FROM ""TB_TOPIC22"" b + limit 1) as6 +FROM ""TB_TOPIC22"" a", subquery); + var subqueryList = select.ToList(a => new + { + all = a, + count = (long)select.As("b").Sum(b => b.Id) + }); + } + [Fact] + public void Min() + { + var subquery = select.ToSql(a => new + { + all = a, + count = select.As("b").Min(b => b.Id) + }); + Assert.Equal(@"SELECT a.""ID"" as1, a.""CLICKS"" as2, a.""TYPEGUID"" as3, a.""TITLE"" as4, a.""CREATETIME"" as5, (SELECT min(b.""ID"") + FROM ""TB_TOPIC22"" b + limit 1) as6 +FROM ""TB_TOPIC22"" a", subquery); + var subqueryList = select.ToList(a => new + { + all = a, + count = select.As("b").Min(b => b.Id) + }); + } + [Fact] + public void Max() + { + var subquery = select.ToSql(a => new + { + all = a, + count = select.As("b").Max(b => b.Id) + }); + Assert.Equal(@"SELECT a.""ID"" as1, a.""CLICKS"" as2, a.""TYPEGUID"" as3, a.""TITLE"" as4, a.""CREATETIME"" as5, (SELECT max(b.""ID"") + FROM ""TB_TOPIC22"" b + limit 1) as6 +FROM ""TB_TOPIC22"" a", subquery); + var subqueryList = select.ToList(a => new + { + all = a, + count = select.As("b").Max(b => b.Id) + }); + } + [Fact] + public void Avg() + { + var subquery = select.ToSql(a => new + { + all = a, + count = select.As("b").Avg(b => b.Id) + }); + Assert.Equal(@"SELECT a.""ID"" as1, a.""CLICKS"" as2, a.""TYPEGUID"" as3, a.""TITLE"" as4, a.""CREATETIME"" as5, (SELECT avg(b.""ID"") + FROM ""TB_TOPIC22"" b + limit 1) as6 +FROM ""TB_TOPIC22"" a", subquery); + var subqueryList = select.ToList(a => new + { + all = a, + count = select.As("b").Avg(b => b.Id) + }); + } + [Fact] + public void WhereIn() + { + var subquery = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToSql(); + Assert.Equal(@"SELECT a.""ID"", a.""CLICKS"", a.""TYPEGUID"", a.""TITLE"", a.""CREATETIME"" +FROM ""TB_TOPIC22"" a +WHERE ((((a.""ID"")::text) in (SELECT b.""TITLE"" + FROM ""TB_TOPIC22"" b)))", subquery); + var subqueryList = select.Where(a => select.As("b").ToList(b => b.Title).Contains(a.Id.ToString())).ToList(); + } + [Fact] + public void As() + { + } + + [Fact] + public void AsTable() + { + + var listt = select.AsTable((a, b) => "(select * from tb_topic where clicks > 10)").Page(1, 10).ToList(); + + Func tableRule = (type, oldname) => + { + if (oldname.Length > 16) oldname = oldname.Remove(16); + if (type == typeof(Topic)) return oldname + "_T1"; + else if (type == typeof(TestTypeInfo)) return oldname + "_T2"; + return oldname + "_AT"; + }; + + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).AsTable(tableRule); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\"", sql); + + query = select.LeftJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx").AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx'", sql); + + query = select.LeftJoin(a => a.Type.Guid == a.TypeGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10).AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTIN_AT\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + + //���û�е������� + query = select.LeftJoin((a, b) => b.Guid == a.TypeGuid).AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" b ON b.\"GUID\" = a.\"TYPEGUID\"", sql); + + query = select.LeftJoin((a, b) => b.Guid == a.TypeGuid && b.Name == "xxx").AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" b ON b.\"GUID\" = a.\"TYPEGUID\" AND b.\"NAME\" = 'xxx'", sql); + + query = select.LeftJoin((a, a__Type) => a__Type.Guid == a.TypeGuid && a__Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10).AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" AND a__Type.\"NAME\" = 'xxx' LEFT JOIN \"TESTTYPEPARENTIN_AT\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\" WHERE (a__Type__Parent.\"ID\" = 10)", sql); + + //������� + query = select + .LeftJoin(a => a.Type.Guid == a.TypeGuid) + .LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId).AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" LEFT JOIN \"TESTTYPEPARENTIN_AT\" a__Type__Parent ON a__Type__Parent.\"ID\" = a__Type.\"PARENTID\"", sql); + + query = select + .LeftJoin((a, a__Type) => a__Type.Guid == a.TypeGuid) + .LeftJoin((a, c) => c.Id == a.Type.ParentId).AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a__Type.\"GUID\", a__Type.\"PARENTID\", a__Type.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" a__Type ON a__Type.\"GUID\" = a.\"TYPEGUID\" LEFT JOIN \"TESTTYPEPARENTIN_AT\" c ON c.\"ID\" = a__Type.\"PARENTID\"", sql); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .LeftJoin(a => a.TypeGuid == b.Guid) + .LeftJoin(a => b.ParentId == c.Id)).AsTable(tableRule); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", b.\"GUID\", b.\"PARENTID\", b.\"NAME\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO_T2\" b ON a.\"TYPEGUID\" = b.\"GUID\" LEFT JOIN \"TESTTYPEPARENTIN_AT\" c ON b.\"PARENTID\" = c.\"ID\"", sql); + + //������϶����㲻�� + query = select.LeftJoin("\"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\"").AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\"", sql); + + query = select.LeftJoin("\"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\" and b.\"NAME\" = @bname", new { bname = "xxx" }).AsTable(tableRule); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22_T1\" a LEFT JOIN \"TESTTYPEINFO\" b on b.\"GUID\" = a.\"TYPEGUID\" and b.\"NAME\" = @bname", sql); + + query = select.AsTable((_, old) => old).AsTable((_, old) => old); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT * from (SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a) ftb UNION ALL SELECT * from (SELECT a.\"ID\", a.\"CLICKS\", a.\"TYPEGUID\", a.\"TITLE\", a.\"CREATETIME\" FROM \"TB_TOPIC22\" a) ftb", sql); + query.ToList(); + + query = select.AsTable((_, old) => old).AsTable((_, old) => old); + sql = query.ToSql("count(1) as1").Replace("\r\n", ""); + Assert.Equal("SELECT * from (SELECT count(1) as1 FROM \"TB_TOPIC22\" a) ftb UNION ALL SELECT * from (SELECT count(1) as1 FROM \"TB_TOPIC22\" a) ftb", sql); + query.Count(); + + select.AsTable((_, old) => old).AsTable((_, old) => old).Max(a => a.Id); + select.AsTable((_, old) => old).AsTable((_, old) => old).Min(a => a.Id); + select.AsTable((_, old) => old).AsTable((_, old) => old).Sum(a => a.Id); + select.AsTable((_, old) => old).AsTable((_, old) => old).Avg(a => a.Id); + + var sqlsss = select + .AsTable((type, old) => type == typeof(Topic) ? $"{old}_1" : null) + .AsTable((type, old) => type == typeof(Topic) ? $"{old}_2" : null) + .ToSql(a => new + { + a.Id, + a.Clicks + }, FieldAliasOptions.AsProperty); + + var slsld3 = select + .AsTable((type, old) => type == typeof(Topic) ? $"({sqlsss})" : null) + .Page(1, 20) + .ToList(a => new + { + a.Id, + a.Clicks + }); + } + + public class TiOtmModel1 + { + [Column(IsIdentity = true)] + public int id { get; set; } + public virtual TiOtmModel2 model2 { get; set; } + + public string m1name { get; set; } + } + public class TiOtmModel2 + { + [Column(IsPrimary = true)] + public int model2id { get; set; } + public virtual TiOtmModel1 model1 { get; set; } + + public string m2setting { get; set; } + + public List childs { get; set; } + } + public class TiOtmModel3 + { + [Column(IsIdentity = true)] + public int id { get; set; } + + public int model2111Idaaa { get; set; } + public string title { get; set; } + + public List childs2 { get; set; } + } + public class TiOtmModel4 + { + [Column(IsIdentity = true)] + public int id { get; set; } + + public int model3333Id333 { get; set; } + public string title444 { get; set; } + } + + [Fact] + public void Include_OneToMany() + { + var model1 = new TiOtmModel1 { m1name = DateTime.Now.Second.ToString() }; + model1.id = (int)g.kingbaseES.Insert(model1).ExecuteIdentity(); + var model2 = new TiOtmModel2 { model2id = model1.id, m2setting = DateTime.Now.Second.ToString() }; + g.kingbaseES.Insert(model2).ExecuteAffrows(); + + var model3_1 = new TiOtmModel3 { model2111Idaaa = model1.id, title = "testmodel3__111" }; + model3_1.id = (int)g.kingbaseES.Insert(model3_1).ExecuteIdentity(); + var model3_2 = new TiOtmModel3 { model2111Idaaa = model1.id, title = "testmodel3__222" }; + model3_2.id = (int)g.kingbaseES.Insert(model3_2).ExecuteIdentity(); + var model3_3 = new TiOtmModel3 { model2111Idaaa = model1.id, title = "testmodel3__333" }; + model3_3.id = (int)g.kingbaseES.Insert(model3_2).ExecuteIdentity(); + + var model4s = new[] { + new TiOtmModel4{ model3333Id333 = model3_1.id, title444 = "testmodel3_4__111" }, + new TiOtmModel4{ model3333Id333 = model3_1.id, title444 = "testmodel3_4__222" }, + new TiOtmModel4{ model3333Id333 = model3_2.id, title444 = "testmodel3_4__111" }, + new TiOtmModel4{ model3333Id333 = model3_2.id, title444 = "testmodel3_4__222" }, + new TiOtmModel4{ model3333Id333 = model3_2.id, title444 = "testmodel3_4__333" } + }; + Assert.Equal(5, g.kingbaseES.Insert(model4s).ExecuteAffrows()); + + var t0 = g.kingbaseES.Select() + .IncludeMany(a => a.childs.Where(m3 => m3.model2111Idaaa == a.model2id)) + .Where(a => a.model2id <= model1.id) + .ToList(); + + var t1 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id)) + .Where(a => a.id <= model1.id) + .ToList(); + + var t2 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id), + then => then.IncludeMany(m3 => m3.childs2.Where(m4 => m4.model3333Id333 == m3.id))) + .Where(a => a.id <= model1.id) + .ToList(); + + var t00 = g.kingbaseES.Select() + .IncludeMany(a => a.childs.Take(1).Where(m3 => m3.model2111Idaaa == a.model2id)) + .Where(a => a.model2id <= model1.id) + .ToList(); + + var t11 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Take(1).Where(m3 => m3.model2111Idaaa == a.model2.model2id)) + .Where(a => a.id <= model1.id) + .ToList(); + + var t22 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Take(1).Where(m3 => m3.model2111Idaaa == a.model2.model2id), + then => then.IncludeMany(m3 => m3.childs2.Take(2).Where(m4 => m4.model3333Id333 == m3.id))) + .Where(a => a.id <= model1.id) + .ToList(); + + //---- Select ---- + + var at0 = g.kingbaseES.Select() + .IncludeMany(a => a.childs.Where(m3 => m3.model2111Idaaa == a.model2id).Select(m3 => new TiOtmModel3 { id = m3.id })) + .Where(a => a.model2id <= model1.id) + .ToList(); + + var at1 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id).Select(m3 => new TiOtmModel3 { id = m3.id })) + .Where(a => a.id <= model1.id) + .ToList(); + + var at2 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2111Idaaa == a.model2.model2id).Select(m3 => new TiOtmModel3 { id = m3.id }), + then => then.IncludeMany(m3 => m3.childs2.Where(m4 => m4.model3333Id333 == m3.id).Select(m4 => new TiOtmModel4 { id = m4.id }))) + .Where(a => a.id <= model1.id) + .ToList(); + + var at00 = g.kingbaseES.Select() + .IncludeMany(a => a.childs.Take(1).Where(m3 => m3.model2111Idaaa == a.model2id).Select(m3 => new TiOtmModel3 { id = m3.id })) + .Where(a => a.model2id <= model1.id) + .ToList(); + + var at11 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Take(1).Where(m3 => m3.model2111Idaaa == a.model2.model2id).Select(m3 => new TiOtmModel3 { id = m3.id })) + .Where(a => a.id <= model1.id) + .ToList(); + + var at22 = g.kingbaseES.Select() + .IncludeMany(a => a.model2.childs.Take(1).Where(m3 => m3.model2111Idaaa == a.model2.model2id).Select(m3 => new TiOtmModel3 { id = m3.id }), + then => then.IncludeMany(m3 => m3.childs2.Take(2).Where(m4 => m4.model3333Id333 == m3.id).Select(m4 => new TiOtmModel4 { id = m4.id }))) + .Where(a => a.id <= model1.id) + .ToList(); + } + + public class TiOtmModel11 + { + [Column(IsIdentity = true)] + public int id { get; set; } + public int model2id { get; set; } + public string m3setting { get; set; } + public TiOtmModel22 model2 { get; set; } + public string m1name { get; set; } + } + + public class TiOtmModel22 + { + [Column(IsIdentity = true)] + public int id { get; set; } + public string m2setting { get; set; } + public string aaa { get; set; } + public string bbb { get; set; } + public List childs { get; set; } + } + public class TiOtmModel33 + { + [Column(IsIdentity = true)] + public int id { get; set; } + public int model2Id { get; set; } + public string title { get; set; } + public string setting { get; set; } + } + [Fact] + public void Include_OneToMany2() + { + string setting = "x"; + var model2 = new TiOtmModel22 { m2setting = DateTime.Now.Second.ToString(), aaa = "aaa" + DateTime.Now.Second, bbb = "bbb" + DateTime.Now.Second }; + model2.id = (int)g.kingbaseES.Insert(model2).ExecuteIdentity(); + + var model3s = new[] + { + new TiOtmModel33 {model2Id = model2.id, title = "testmodel3__111", setting = setting}, + new TiOtmModel33 {model2Id = model2.id, title = "testmodel3__222", setting = setting}, + new TiOtmModel33 {model2Id = model2.id, title = "testmodel3__333", setting = setting} + }; + Assert.Equal(3, g.kingbaseES.Insert(model3s).ExecuteAffrows()); + + var model1 = new TiOtmModel11 { m1name = DateTime.Now.Second.ToString(), model2id = model2.id, m3setting = setting }; + model1.id = (int)g.kingbaseES.Insert(model1).ExecuteIdentity(); + + var t1 = g.kingbaseES.Select() + .LeftJoin(a => a.model2id == a.model2.id) + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2Id == a.model2.id && m3.setting == a.m3setting)) + .Where(a => a.id <= model1.id) + .ToList(true); + + var t11 = g.kingbaseES.Select() + .LeftJoin(a => a.model2id == a.model2.id) + .IncludeMany(a => a.model2.childs.Take(1).Where(m3 => m3.model2Id == a.model2.id && m3.setting == a.m3setting)) + .Where(a => a.id <= model1.id) + .ToList(true); + + //---- Select ---- + + var at1 = g.kingbaseES.Select() + .LeftJoin(a => a.model2id == a.model2.id) + .IncludeMany(a => a.model2.childs.Where(m3 => m3.model2Id == a.model2.id && m3.setting == a.m3setting).Select(m3 => new TiOtmModel33 { title = m3.title })) + .Where(a => a.id <= model1.id) + .ToList(true); + + var at11 = g.kingbaseES.Select() + .LeftJoin(a => a.model2id == a.model2.id) + .IncludeMany(a => a.model2.childs.Take(1).Where(m3 => m3.model2Id == a.model2.id && m3.setting == a.m3setting).Select(m3 => new TiOtmModel33 { title = m3.title })) + .Where(a => a.id <= model1.id) + .ToList(true); + } + + [Fact] + public void Include_OneToChilds() + { + var tag1 = new Tag + { + Ddd = DateTime.Now.Second, + Name = "test_oneToChilds_01_中国" + }; + tag1.Id = (int)g.kingbaseES.Insert(tag1).ExecuteIdentity(); + var tag1_1 = new Tag + { + Parent_id = tag1.Id, + Ddd = DateTime.Now.Second, + Name = "test_oneToChilds_01_北京" + }; + tag1_1.Id = (int)g.kingbaseES.Insert(tag1_1).ExecuteIdentity(); + var tag1_2 = new Tag + { + Parent_id = tag1.Id, + Ddd = DateTime.Now.Second, + Name = "test_oneToChilds_01_上海" + }; + tag1_2.Id = (int)g.kingbaseES.Insert(tag1_2).ExecuteIdentity(); + + var tag2 = new Tag + { + Ddd = DateTime.Now.Second, + Name = "test_oneToChilds_02_美国" + }; + tag2.Id = (int)g.kingbaseES.Insert(tag2).ExecuteIdentity(); + var tag2_1 = new Tag + { + Parent_id = tag2.Id, + Ddd = DateTime.Now.Second, + Name = "test_oneToChilds_02_纽约" + }; + tag2_1.Id = (int)g.kingbaseES.Insert(tag2_1).ExecuteIdentity(); + var tag2_2 = new Tag + { + Parent_id = tag2.Id, + Ddd = DateTime.Now.Second, + Name = "test_oneToChilds_02_华盛顿" + }; + tag2_2.Id = (int)g.kingbaseES.Insert(tag2_2).ExecuteIdentity(); + + var tags0 = g.kingbaseES.Select() + .Include(a => a.Parent) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var tags1 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var tags2 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags, + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs)) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var tags3 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags, + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs).IncludeMany(a => a.Tags)) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var tags11 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1)) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Take(1)) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var tags22 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1), + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs.Take(1))) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Take(1)) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var tags33 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1), + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs.Take(1)).IncludeMany(a => a.Tags.Take(1))) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Take(1)) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + // --- Select --- + + var atags0 = g.kingbaseES.Select() + .Include(a => a.Parent) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var atags1 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name })) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var atags2 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name }), + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs)) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var atags3 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name }), + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs.Select(b => new Song { Id = b.Id, Title = b.Title })).IncludeMany(a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name }))) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var atags11 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1).Select(b => new Tag { Id = b.Id, Name = b.Name })) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var atags22 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1).Select(b => new Tag { Id = b.Id, Name = b.Name }), + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title }))) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + + var atags33 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1).Select(b => new Tag { Id = b.Id, Name = b.Name }), + then => then.Include(a => a.Parent).IncludeMany(a => a.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title })).IncludeMany(a => a.Tags.Take(1).Select(b => new Tag { Id = b.Id, Name = b.Name }))) + .Include(a => a.Parent) + .IncludeMany(a => a.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Id == tag1.Id || a.Id == tag2.Id) + .ToList(); + } + + [Fact] + public void Include_ManyToMany() + { + + var tag1 = new Tag + { + Ddd = DateTime.Now.Second, + Name = "test_manytoMany_01_中国" + }; + tag1.Id = (int)g.kingbaseES.Insert(tag1).ExecuteIdentity(); + var tag2 = new Tag + { + Ddd = DateTime.Now.Second, + Name = "test_manytoMany_02_美国" + }; + tag2.Id = (int)g.kingbaseES.Insert(tag2).ExecuteIdentity(); + var tag3 = new Tag + { + Ddd = DateTime.Now.Second, + Name = "test_manytoMany_03_日本" + }; + tag3.Id = (int)g.kingbaseES.Insert(tag3).ExecuteIdentity(); + + var song1 = new Song + { + Create_time = DateTime.Now, + Title = "test_manytoMany_01_我是中国人.mp3", + Url = "http://ww.baidu.com/" + }; + song1.Id = (int)g.kingbaseES.Insert(song1).ExecuteIdentity(); + var song2 = new Song + { + Create_time = DateTime.Now, + Title = "test_manytoMany_02_爱你一万年.mp3", + Url = "http://ww.163.com/" + }; + song2.Id = (int)g.kingbaseES.Insert(song2).ExecuteIdentity(); + var song3 = new Song + { + Create_time = DateTime.Now, + Title = "test_manytoMany_03_千年等一回.mp3", + Url = "http://ww.sina.com/" + }; + song3.Id = (int)g.kingbaseES.Insert(song3).ExecuteIdentity(); + + g.kingbaseES.Insert(new Song_tag { Song_id = song1.Id, Tag_id = tag1.Id }).ExecuteAffrows(); + g.kingbaseES.Insert(new Song_tag { Song_id = song2.Id, Tag_id = tag1.Id }).ExecuteAffrows(); + g.kingbaseES.Insert(new Song_tag { Song_id = song3.Id, Tag_id = tag1.Id }).ExecuteAffrows(); + g.kingbaseES.Insert(new Song_tag { Song_id = song1.Id, Tag_id = tag2.Id }).ExecuteAffrows(); + g.kingbaseES.Insert(new Song_tag { Song_id = song3.Id, Tag_id = tag2.Id }).ExecuteAffrows(); + g.kingbaseES.Insert(new Song_tag { Song_id = song3.Id, Tag_id = tag3.Id }).ExecuteAffrows(); + + var songs1 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs1.Count); + Assert.Equal(2, songs1[0].Tags.Count); + Assert.Equal(1, songs1[1].Tags.Count); + Assert.Equal(3, songs1[2].Tags.Count); + + var songs2 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags, + then => then.IncludeMany(t => t.Songs)) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs2.Count); + Assert.Equal(2, songs2[0].Tags.Count); + Assert.Equal(1, songs2[1].Tags.Count); + Assert.Equal(3, songs2[2].Tags.Count); + + var tags3 = g.kingbaseES.Select() + .Include(a => a.Tag.Parent) + .IncludeMany(a => a.Tag.Songs) + .Where(a => a.Tag.Id == tag1.Id || a.Tag.Id == tag2.Id) + .ToList(true); + + + var songs11 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1)) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs11.Count); + Assert.Equal(1, songs11[0].Tags.Count); + Assert.Equal(1, songs11[1].Tags.Count); + Assert.Equal(1, songs11[2].Tags.Count); + + var songs22 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1), + then => then.IncludeMany(t => t.Songs.Take(1))) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs22.Count); + Assert.Equal(1, songs22[0].Tags.Count); + Assert.Equal(1, songs22[1].Tags.Count); + Assert.Equal(1, songs22[2].Tags.Count); + + var tags33 = g.kingbaseES.Select() + .Include(a => a.Tag.Parent) + .IncludeMany(a => a.Tag.Songs.Take(1)) + .Where(a => a.Tag.Id == tag1.Id || a.Tag.Id == tag2.Id) + .ToList(true); + + // --- Select --- + + new List(new[] { song1, song2, song3 }).IncludeMany(g.kingbaseES, a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name })); + + var asongs1 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name })) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs1.Count); + Assert.Equal(2, songs1[0].Tags.Count); + Assert.Equal(1, songs1[1].Tags.Count); + Assert.Equal(3, songs1[2].Tags.Count); + + var asongs2 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Select(b => new Tag { Id = b.Id, Name = b.Name }), + then => then.IncludeMany(t => t.Songs.Select(b => new Song { Id = b.Id, Title = b.Title }))) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs2.Count); + Assert.Equal(2, songs2[0].Tags.Count); + Assert.Equal(1, songs2[1].Tags.Count); + Assert.Equal(3, songs2[2].Tags.Count); + + var atags3 = g.kingbaseES.Select() + .Include(a => a.Tag.Parent) + .IncludeMany(a => a.Tag.Songs.Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Tag.Id == tag1.Id || a.Tag.Id == tag2.Id) + .ToList(true); + + + var asongs11 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1).Select(b => new Tag { Id = b.Id, Name = b.Name })) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs11.Count); + Assert.Equal(1, songs11[0].Tags.Count); + Assert.Equal(1, songs11[1].Tags.Count); + Assert.Equal(1, songs11[2].Tags.Count); + + var asongs22 = g.kingbaseES.Select() + .IncludeMany(a => a.Tags.Take(1).Select(b => new Tag { Id = b.Id, Name = b.Name }), + then => then.IncludeMany(t => t.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title }))) + .Where(a => a.Id == song1.Id || a.Id == song2.Id || a.Id == song3.Id) + .ToList(); + Assert.Equal(3, songs22.Count); + Assert.Equal(1, songs22[0].Tags.Count); + Assert.Equal(1, songs22[1].Tags.Count); + Assert.Equal(1, songs22[2].Tags.Count); + + var atags33 = g.kingbaseES.Select() + .Include(a => a.Tag.Parent) + .IncludeMany(a => a.Tag.Songs.Take(1).Select(b => new Song { Id = b.Id, Title = b.Title })) + .Where(a => a.Tag.Id == tag1.Id || a.Tag.Id == tag2.Id) + .ToList(true); + } + + public class ToDel1Pk + { + [Column(IsIdentity = true)] + public int id { get; set; } + public string name { get; set; } + } + public class ToDel2Pk + { + [Column(IsPrimary = true)] + public Guid pk1 { get; set; } + [Column(IsPrimary = true)] + public string pk2 { get; set; } + public string name { get; set; } + } + public class ToDel3Pk + { + [Column(IsPrimary = true)] + public Guid pk1 { get; set; } + [Column(IsPrimary = true)] + public int pk2 { get; set; } + [Column(IsPrimary = true)] + public string pk3 { get; set; } + public string name { get; set; } + } + [Fact] + public void ToDelete() + { + g.kingbaseES.Select().ToDelete().ExecuteAffrows(); + Assert.Equal(0, g.kingbaseES.Select().Count()); + g.kingbaseES.Insert(new[] { + new ToDel1Pk{ name = "name1"}, + new ToDel1Pk{ name = "name2"}, + new ToDel1Pk{ name = "nick1"}, + new ToDel1Pk{ name = "nick2"}, + new ToDel1Pk{ name = "nick3"} + }).ExecuteAffrows(); + Assert.Equal(2, g.kingbaseES.Select().Where(a => a.name.StartsWith("name")).ToDelete().ExecuteAffrows()); + Assert.Equal(3, g.kingbaseES.Select().Count()); + Assert.Equal(3, g.kingbaseES.Select().Where(a => a.name.StartsWith("nick")).Count()); + + g.kingbaseES.Select().ToDelete().ExecuteAffrows(); + Assert.Equal(0, g.kingbaseES.Select().Count()); + g.kingbaseES.Insert(new[] { + new ToDel2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "name1"}, + new ToDel2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "name2"}, + new ToDel2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "nick1"}, + new ToDel2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "nick2"}, + new ToDel2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "nick3"} + }).ExecuteAffrows(); + Assert.Equal(2, g.kingbaseES.Select().Where(a => a.name.StartsWith("name")).ToDelete().ExecuteAffrows()); + Assert.Equal(3, g.kingbaseES.Select().Count()); + Assert.Equal(3, g.kingbaseES.Select().Where(a => a.name.StartsWith("nick")).Count()); + + g.kingbaseES.Select().ToDelete().ExecuteAffrows(); + Assert.Equal(0, g.kingbaseES.Select().Count()); + g.kingbaseES.Insert(new[] { + new ToDel3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "name1"}, + new ToDel3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "name2"}, + new ToDel3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "nick1"}, + new ToDel3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "nick2"}, + new ToDel3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "nick3"} + }).ExecuteAffrows(); + Assert.Equal(2, g.kingbaseES.Select().Where(a => a.name.StartsWith("name")).ToDelete().ExecuteAffrows()); + Assert.Equal(3, g.kingbaseES.Select().Count()); + Assert.Equal(3, g.kingbaseES.Select().Where(a => a.name.StartsWith("nick")).Count()); + } + + public class ToUpd1Pk + { + [Column(IsIdentity = true)] + public int id { get; set; } + public string name { get; set; } + } + public class ToUpd2Pk + { + [Column(IsPrimary = true)] + public Guid pk1 { get; set; } + [Column(IsPrimary = true)] + public string pk2 { get; set; } + public string name { get; set; } + } + public class ToUpd3Pk + { + [Column(IsPrimary = true)] + public Guid pk1 { get; set; } + [Column(IsPrimary = true)] + public int pk2 { get; set; } + [Column(IsPrimary = true)] + public string pk3 { get; set; } + public string name { get; set; } + } + [Fact] + public void ToUpdate() + { + g.kingbaseES.Select().ToDelete().ExecuteAffrows(); + Assert.Equal(0, g.kingbaseES.Select().Count()); + g.kingbaseES.Insert(new[] { + new ToUpd1Pk{ name = "name1"}, + new ToUpd1Pk{ name = "name2"}, + new ToUpd1Pk{ name = "nick1"}, + new ToUpd1Pk{ name = "nick2"}, + new ToUpd1Pk{ name = "nick3"} + }).ExecuteAffrows(); + Assert.Equal(2, g.kingbaseES.Select().Where(a => a.name.StartsWith("name")).ToUpdate().Set(a => a.name, "nick?").ExecuteAffrows()); + Assert.Equal(5, g.kingbaseES.Select().Count()); + Assert.Equal(5, g.kingbaseES.Select().Where(a => a.name.StartsWith("nick")).Count()); + + g.kingbaseES.Select().ToDelete().ExecuteAffrows(); + Assert.Equal(0, g.kingbaseES.Select().Count()); + g.kingbaseES.Insert(new[] { + new ToUpd2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "name1"}, + new ToUpd2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "name2"}, + new ToUpd2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "nick1"}, + new ToUpd2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "nick2"}, + new ToUpd2Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = "pk2", name = "nick3"} + }).ExecuteAffrows(); + Assert.Equal(2, g.kingbaseES.Select().Where(a => a.name.StartsWith("name")).ToUpdate().Set(a => a.name, "nick?").ExecuteAffrows()); + Assert.Equal(5, g.kingbaseES.Select().Count()); + Assert.Equal(5, g.kingbaseES.Select().Where(a => a.name.StartsWith("nick")).Count()); + + g.kingbaseES.Select().ToDelete().ExecuteAffrows(); + Assert.Equal(0, g.kingbaseES.Select().Count()); + g.kingbaseES.Insert(new[] { + new ToUpd3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "name1"}, + new ToUpd3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "name2"}, + new ToUpd3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "nick1"}, + new ToUpd3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "nick2"}, + new ToUpd3Pk{ pk1 = FreeUtil.NewMongodbId(), pk2 = 1, pk3 = "pk3", name = "nick3"} + }).ExecuteAffrows(); + Assert.Equal(2, g.kingbaseES.Select().Where(a => a.name.StartsWith("name")).ToUpdate().Set(a => a.name, "nick?").ExecuteAffrows()); + Assert.Equal(5, g.kingbaseES.Select().Count()); + Assert.Equal(5, g.kingbaseES.Select().Where(a => a.name.StartsWith("nick")).Count()); + } + + [Fact] + public void ForUpdate() + { + var orm = g.kingbaseES; + + Assert.Equal("安全起见,请务必在事务开启之后,再使用 ForUpdate", + Assert.Throws(() => orm.Select().ForUpdate().Limit(1).ToList())?.Message); + + orm.Transaction(() => + { + var sql = orm.Select().ForUpdate().Limit(1).ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"NAME\" FROM \"TOUPD1PK\" a limit 1 for update", sql); + orm.Select().ForUpdate().Limit(1).ToList(); + + sql = orm.Select().ForUpdate(true).Limit(1).ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.\"ID\", a.\"NAME\" FROM \"TOUPD1PK\" a limit 1 for update nowait", sql); + orm.Select().ForUpdate(true).Limit(1).ToList(); + }); + } + + [Fact] + public void ToTreeList() + { + var fsql = g.kingbaseES; + fsql.Delete().Where("1=1").ExecuteAffrows(); + var repo = fsql.GetRepository(); + repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; + repo.DbContextOptions.NoneParameter = true; + repo.Insert(new VM_District_Child + { + Code = "100000", + Name = "中国", + Childs = new List(new[] { + new VM_District_Child + { + Code = "110000", + Name = "北京", + Childs = new List(new[] { + new VM_District_Child{ Code="110100", Name = "北京市" }, + new VM_District_Child{ Code="110101", Name = "东城区" }, + }) + } + }) + }); + + var t1 = fsql.Select() + .InnerJoin(a => a.ParentCode == a.Parent.Code) + .Where(a => a.Code == "110101") + .ToList(true); + Assert.Single(t1); + Assert.Equal("110101", t1[0].Code); + Assert.NotNull(t1[0].Parent); + Assert.Equal("110000", t1[0].Parent.Code); + + var t2 = fsql.Select() + .InnerJoin(a => a.ParentCode == a.Parent.Code) + .InnerJoin(a => a.Parent.ParentCode == a.Parent.Parent.Code) + .Where(a => a.Code == "110101") + .ToList(true); + Assert.Single(t2); + Assert.Equal("110101", t2[0].Code); + Assert.NotNull(t2[0].Parent); + Assert.Equal("110000", t2[0].Parent.Code); + Assert.NotNull(t2[0].Parent.Parent); + Assert.Equal("100000", t2[0].Parent.Parent.Code); + + var t3 = fsql.Select().ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToTreeList(); + Assert.Single(t3); + Assert.Equal("100000", t3[0].Code); + Assert.Single(t3[0].Childs); + Assert.Equal("110000", t3[0].Childs[0].Code); + Assert.Equal(2, t3[0].Childs[0].Childs.Count); + Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); + Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code); + + t3 = fsql.Select().Where(a => a.Name == "中国").AsTreeCte().OrderBy(a => a.Code).ToList(); + Assert.Equal(4, t3.Count); + Assert.Equal("100000", t3[0].Code); + Assert.Equal("110000", t3[1].Code); + Assert.Equal("110100", t3[2].Code); + Assert.Equal("110101", t3[3].Code); + + t3 = fsql.Select().Where(a => a.Name == "北京").AsTreeCte().OrderBy(a => a.Code).ToList(); + Assert.Equal(3, t3.Count); + Assert.Equal("110000", t3[0].Code); + Assert.Equal("110100", t3[1].Code); + Assert.Equal("110101", t3[2].Code); + + var t4 = fsql.Select().Where(a => a.Name == "中国").AsTreeCte(a => a.Name).OrderBy(a => a.Code) + .ToList(a => new { item = a, level = Convert.ToInt32("a.cte_level"), path = "a.cte_path" }); + Assert.Equal(4, t4.Count); + Assert.Equal("100000", t4[0].item.Code); + Assert.Equal("110000", t4[1].item.Code); + Assert.Equal("110100", t4[2].item.Code); + Assert.Equal("110101", t4[3].item.Code); + Assert.Equal("中国", t4[0].path); + Assert.Equal("中国 -> 北京", t4[1].path); + Assert.Equal("中国 -> 北京 -> 北京市", t4[2].path); + Assert.Equal("中国 -> 北京 -> 东城区", t4[3].path); + + t4 = fsql.Select().Where(a => a.Name == "中国").AsTreeCte(a => a.Name + "[" + a.Code + "]").OrderBy(a => a.Code) + .ToList(a => new { item = a, level = Convert.ToInt32("a.cte_level"), path = "a.cte_path" }); + Assert.Equal(4, t4.Count); + Assert.Equal("100000", t4[0].item.Code); + Assert.Equal("110000", t4[1].item.Code); + Assert.Equal("110100", t4[2].item.Code); + Assert.Equal("110101", t4[3].item.Code); + Assert.Equal("中国[100000]", t4[0].path); + Assert.Equal("中国[100000] -> 北京[110000]", t4[1].path); + Assert.Equal("中国[100000] -> 北京[110000] -> 北京市[110100]", t4[2].path); + Assert.Equal("中国[100000] -> 北京[110000] -> 东城区[110101]", t4[3].path); + + var select = fsql.Select() + .Where(a => a.Name == "中国") + .AsTreeCte() + //.OrderBy("a.cte_level desc") //递归层级 + ; + // var list = select.ToList(); //自己调试看查到的数据 + select.ToUpdate().Set(a => a.testint, 855).ExecuteAffrows(); + Assert.Equal(855, fsql.Select() + .Where(a => a.Name == "中国") + .AsTreeCte().Distinct().First(a => a.testint)); + + Assert.Equal(4, select.ToDelete().ExecuteAffrows()); + Assert.False(fsql.Select() + .Where(a => a.Name == "中国") + .AsTreeCte().Any()); + } + + [Table(Name = "D_District")] + public class BaseDistrict + { + [Column(IsPrimary = true, StringLength = 6)] + public string Code { get; set; } + + [Column(StringLength = 20, IsNullable = false)] + public string Name { get; set; } + + [Column(StringLength = 6)] + public virtual string ParentCode { get; set; } + + public int testint { get; set; } + } + [Table(Name = "D_District", DisableSyncStructure = true)] + public class VM_District_Child : BaseDistrict + { + public override string ParentCode { get => base.ParentCode; set => base.ParentCode = value; } + + [Navigate(nameof(ParentCode))] + public List Childs { get; set; } + } + [Table(Name = "D_District", DisableSyncStructure = true)] + public class VM_District_Parent : BaseDistrict + { + public override string ParentCode { get => base.ParentCode; set => base.ParentCode = value; } + + [Navigate(nameof(ParentCode))] + public VM_District_Parent Parent { get; set; } + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESUpdateTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESUpdateTest.cs new file mode 100644 index 00000000..021d4b5d --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/KingbaseESUpdateTest.cs @@ -0,0 +1,190 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESUpdateTest + { + IUpdate update => g.kingbaseES.Update(); + + [Table(Name = "tb_topic")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int? Clicks { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void Dywhere() + { + Assert.Null(g.kingbaseES.Update().ToSql()); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='test' \r\nWHERE (\"ID\" IN (1,2))", g.kingbaseES.Update(new[] { 1, 2 }).SetRaw("title='test'").ToSql()); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='test1' \r\nWHERE (\"ID\" = 1)", g.kingbaseES.Update(new Topic { Id = 1, Title = "test" }).SetRaw("title='test1'").ToSql()); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='test1' \r\nWHERE (\"ID\" IN (1,2))", g.kingbaseES.Update(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).SetRaw("title='test1'").ToSql()); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='test1' \r\nWHERE (\"ID\" = 1)", g.kingbaseES.Update(new { id = 1 }).SetRaw("title='test1'").ToSql()); + } + + [Fact] + public void SetSource() + { + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = NULL, \"TITLE\" = 'newtitle', \"CREATETIME\" = '0001-01-01 00:00:00.000000' WHERE (\"ID\" = 1)", sql); + + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + items[0].Clicks = null; + + sql = update.SetSource(items).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = CASE \"ID\" WHEN 1 THEN NULL WHEN 2 THEN 100 WHEN 3 THEN 200 WHEN 4 THEN 300 WHEN 5 THEN 400 WHEN 6 THEN 500 WHEN 7 THEN 600 WHEN 8 THEN 700 WHEN 9 THEN 800 WHEN 10 THEN 900 END::int4, \"TITLE\" = CASE \"ID\" WHEN 1 THEN 'newtitle0' WHEN 2 THEN 'newtitle1' WHEN 3 THEN 'newtitle2' WHEN 4 THEN 'newtitle3' WHEN 5 THEN 'newtitle4' WHEN 6 THEN 'newtitle5' WHEN 7 THEN 'newtitle6' WHEN 8 THEN 'newtitle7' WHEN 9 THEN 'newtitle8' WHEN 10 THEN 'newtitle9' END::text, \"CREATETIME\" = CASE \"ID\" WHEN 1 THEN '0001-01-01 00:00:00.000000' WHEN 2 THEN '0001-01-01 00:00:00.000000' WHEN 3 THEN '0001-01-01 00:00:00.000000' WHEN 4 THEN '0001-01-01 00:00:00.000000' WHEN 5 THEN '0001-01-01 00:00:00.000000' WHEN 6 THEN '0001-01-01 00:00:00.000000' WHEN 7 THEN '0001-01-01 00:00:00.000000' WHEN 8 THEN '0001-01-01 00:00:00.000000' WHEN 9 THEN '0001-01-01 00:00:00.000000' WHEN 10 THEN '0001-01-01 00:00:00.000000' END::timestamp WHERE (\"ID\" IN (1,2,3,4,5,6,7,8,9,10))", sql); + + sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"TITLE\" = CASE \"ID\" WHEN 1 THEN 'newtitle0' WHEN 2 THEN 'newtitle1' WHEN 3 THEN 'newtitle2' WHEN 4 THEN 'newtitle3' WHEN 5 THEN 'newtitle4' WHEN 6 THEN 'newtitle5' WHEN 7 THEN 'newtitle6' WHEN 8 THEN 'newtitle7' WHEN 9 THEN 'newtitle8' WHEN 10 THEN 'newtitle9' END::text WHERE (\"ID\" IN (1,2,3,4,5,6,7,8,9,10))", sql); + + sql = update.SetSource(items).Set(a => a.CreateTime, new DateTime(2020, 1, 1)).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CREATETIME\" = '2020-01-01 00:00:00.000000' WHERE (\"ID\" IN (1,2,3,4,5,6,7,8,9,10))", sql); + + if (g.kingbaseES.Select().Where(a => a.id1 == 1 && a.id2 == 7).Any() == false) + g.kingbaseES.Insert(new ts_source_mpk { id1 = 1, id2 = 7 }).ExecuteAffrows(); + if (g.kingbaseES.Select().Where(a => a.id1 == 1 && a.id2 == 8).Any() == false) + g.kingbaseES.Insert(new ts_source_mpk { id1 = 1, id2 = 8 }).ExecuteAffrows(); + + sql = g.kingbaseES.Update().SetSource(new[] { + new ts_source_mpk { id1 = 1, id2 = 7, xx = "a1" }, + new ts_source_mpk { id1 = 1, id2 = 8, xx = "b122" } + }).NoneParameter().ToSql().Replace("\r\n", ""); + g.kingbaseES.Update().SetSource(new[] { + new ts_source_mpk { id1 = 1, id2 = 7, xx = "a1" }, + new ts_source_mpk { id1 = 1, id2 = 8, xx = "b122" } + }).NoneParameter().ExecuteAffrows(); + var testlist = g.kingbaseES.Select().ToList(); + } + public class ts_source_mpk + { + [Column(IsPrimary = true)] + public int id1 { get; set; } + [Column(IsPrimary = true)] + public int id2 { get; set; } + public string xx { get; set; } + } + [Fact] + public void SetSourceIgnore() + { + Assert.Equal("UPDATE \"TSSI01\" SET \"TINT\" = 10 WHERE (\"ID\" = '00000000-0000-0000-0000-000000000000')", + g.kingbaseES.Update().NoneParameter() + .SetSourceIgnore(new tssi01 { id = Guid.Empty, tint = 10 }, col => col == null).ToSql().Replace("\r\n", "")); + } + public class tssi01 + { + [Column(CanUpdate = false)] + public Guid id { get; set; } + public int tint { get; set; } + public string title { get; set; } + } + [Fact] + public void IgnoreColumns() + { + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"TITLE\" = 'newtitle' WHERE (\"ID\" = 1)", sql); + } + [Fact] + public void UpdateColumns() + { + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).UpdateColumns(a => a.Title).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"TITLE\" = 'newtitle' WHERE (\"ID\" = 1)", sql); + } + [Fact] + public void Set() + { + var sql = update.Where(a => a.Id == 1).Set(a => a.Title, "newtitle").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"TITLE\" = 'newtitle' WHERE (\"ID\" = 1)", sql); + + sql = update.Where(a => a.Id == 1).Set(a => a.Title, "newtitle").Set(a => a.CreateTime, new DateTime(2020, 1, 1)).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"TITLE\" = 'newtitle', \"CREATETIME\" = '2020-01-01 00:00:00.000000' WHERE (\"ID\" = 1)", sql); + + sql = update.Set(a => a.Clicks * 10 / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = coalesce(\"CLICKS\", 0) * 10 / 1 WHERE (\"ID\" = 1)", sql); + + sql = update.Set(a => a.Id - 10).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"ID\" = (\"ID\" - 10) WHERE (\"ID\" = 1)", sql); + + int incrv = 10; + sql = update.Set(a => a.Clicks * incrv / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = coalesce(\"CLICKS\", 0) * 10 / 1 WHERE (\"ID\" = 1)", sql); + + sql = update.Set(a => a.Id - incrv).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"ID\" = (\"ID\" - 10) WHERE (\"ID\" = 1)", sql); + + sql = update.Set(a => a.Clicks == a.Clicks * 10 / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = \"CLICKS\" * 10 / 1 WHERE (\"ID\" = 1)", sql); + + var dt2000 = DateTime.Parse("2000-01-01"); + sql = update.Set(a => a.Clicks == (a.CreateTime > dt2000 ? 1 : 2)).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = case when \"CREATETIME\" > '2000-01-01 00:00:00.000000' then 1 else 2 end WHERE (\"ID\" = 1)", sql); + + sql = update.Set(a => a.Id == 10).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"ID\" = 10 WHERE (\"ID\" = 1)", sql); + + sql = update.Set(a => a.Clicks == null).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = NULL WHERE (\"ID\" = 1)", sql); + } + [Fact] + public void SetRaw() + { + var sql = update.Where(a => a.Id == 1).SetRaw("clicks = clicks + ?", new { incrClick = 1 }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET clicks = clicks + ? WHERE (\"ID\" = 1)", sql); + } + [Fact] + public void SetDto() + { + var sql = update.SetDto(new { clicks = 1, title = "xxx" }).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = 1, \"TITLE\" = 'xxx' WHERE (\"ID\" = 1)", sql); + + sql = update.SetDto(new Dictionary { ["clicks"] = 1, ["title"] = "xxx" }).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET \"CLICKS\" = 1, \"TITLE\" = 'xxx' WHERE (\"ID\" = 1)", sql); + } + [Fact] + public void Where() + { + var sql = update.Where(a => a.Id == 1).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='newtitle' WHERE (\"ID\" = 1)", sql); + + sql = update.Where("id = ?", new { id = 1 }).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='newtitle' WHERE (id = ?)", sql); + + var item = new Topic { Id = 1, Title = "newtitle" }; + sql = update.Where(item).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='newtitle' WHERE (\"ID\" = 1)", sql); + + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + sql = update.Where(items).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE \"TB_TOPIC\" SET title='newtitle' WHERE (\"ID\" IN (1,2,3,4,5,6,7,8,9,10))", sql); + } + [Fact] + public void ExecuteAffrows() + { + + } + [Fact] + public void ExecuteUpdated() + { + + } + + [Fact] + public void AsTable() + { + Assert.Null(g.kingbaseES.Update().ToSql()); + Assert.Equal("UPDATE \"TB_TOPICASTABLE\" SET title='test' \r\nWHERE (\"ID\" IN (1,2))", g.kingbaseES.Update(new[] { 1, 2 }).SetRaw("title='test'").AsTable(a => "tb_topicAsTable").ToSql()); + Assert.Equal("UPDATE \"TB_TOPICASTABLE\" SET title='test1' \r\nWHERE (\"ID\" = 1)", g.kingbaseES.Update(new Topic { Id = 1, Title = "test" }).SetRaw("title='test1'").AsTable(a => "tb_topicAsTable").ToSql()); + Assert.Equal("UPDATE \"TB_TOPICASTABLE\" SET title='test1' \r\nWHERE (\"ID\" IN (1,2))", g.kingbaseES.Update(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).SetRaw("title='test1'").AsTable(a => "tb_topicAsTable").ToSql()); + Assert.Equal("UPDATE \"TB_TOPICASTABLE\" SET title='test1' \r\nWHERE (\"ID\" = 1)", g.kingbaseES.Update(new { id = 1 }).SetRaw("title='test1'").AsTable(a => "tb_topicAsTable").ToSql()); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/OnConflictDoUpdateTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/OnConflictDoUpdateTest.cs new file mode 100644 index 00000000..8dd53840 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/Curd/OnConflictDoUpdateTest.cs @@ -0,0 +1,158 @@ +using FreeSql.DataAnnotations; +using FreeSql.KingbaseES; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class OnConflictDoUpdateTest + { + class TestOnConflictDoUpdateInfo + { + [Column(IsIdentity = true)] + public int id { get; set; } + public string title { get; set; } + public DateTime? time { get; set; } + } + + [Fact] + public void ExecuteAffrows() + { + g.kingbaseES.Delete(new[] { 100, 101, 102 }).ExecuteAffrows(); + var odku1 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new TestOnConflictDoUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity()); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"", ""TIME"") VALUES(100, 'title-100', '2000-01-01 00:00:00.000000') +ON CONFLICT(""ID"") DO UPDATE SET +""TITLE"" = EXCLUDED.""TITLE"", +""TIME"" = EXCLUDED.""TIME""", odku1.ToSql()); + Assert.Equal(1, odku1.ExecuteAffrows()); + + var odku2 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new[] { + new TestOnConflictDoUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 101, title = "title-101", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 102, title = "title-102", time = DateTime.Parse("2000-01-01") } + }).NoneParameter().InsertIdentity()); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"", ""TIME"") VALUES(100, 'title-100', '2000-01-01 00:00:00.000000'), (101, 'title-101', '2000-01-01 00:00:00.000000'), (102, 'title-102', '2000-01-01 00:00:00.000000') +ON CONFLICT(""ID"") DO UPDATE SET +""TITLE"" = EXCLUDED.""TITLE"", +""TIME"" = EXCLUDED.""TIME""", odku2.ToSql()); + odku2.ExecuteAffrows(); + } + + [Fact] + public void IgnoreColumns() + { + g.kingbaseES.Delete(new[] { 200, 201, 202 }).ExecuteAffrows(); + var odku1 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity()); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(200, 'title-200') +ON CONFLICT(""ID"") DO UPDATE SET +""TITLE"" = EXCLUDED.""TITLE"", +""TIME"" = '2000-01-01 00:00:00.000000'", odku1.ToSql()); + Assert.Equal(1, odku1.ExecuteAffrows()); + + var odku2 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new[] { + new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") } + }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity()); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202') +ON CONFLICT(""ID"") DO UPDATE SET +""TITLE"" = EXCLUDED.""TITLE"", +""TIME"" = CASE EXCLUDED.""ID"" +WHEN 200 THEN '2000-01-01 00:00:00.000000' +WHEN 201 THEN '2000-01-01 00:00:00.000000' +WHEN 202 THEN '2000-01-01 00:00:00.000000' END::timestamp", odku2.ToSql()); + odku2.ExecuteAffrows(); + + + g.kingbaseES.Delete(new[] { 200, 201, 202 }).ExecuteAffrows(); + odku1 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity()).IgnoreColumns(a => a.title); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(200, 'title-200') +ON CONFLICT(""ID"") DO UPDATE SET +""TIME"" = '2000-01-01 00:00:00.000000'", odku1.ToSql()); + Assert.Equal(1, odku1.ExecuteAffrows()); + + odku2 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new[] { + new TestOnConflictDoUpdateInfo { id = 200, title = "title-200", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 201, title = "title-201", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 202, title = "title-202", time = DateTime.Parse("2000-01-01") } + }).IgnoreColumns(a => a.time).NoneParameter().InsertIdentity()).IgnoreColumns(a => a.title); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(200, 'title-200'), (201, 'title-201'), (202, 'title-202') +ON CONFLICT(""ID"") DO UPDATE SET +""TIME"" = CASE EXCLUDED.""ID"" +WHEN 200 THEN '2000-01-01 00:00:00.000000' +WHEN 201 THEN '2000-01-01 00:00:00.000000' +WHEN 202 THEN '2000-01-01 00:00:00.000000' END::timestamp", odku2.ToSql()); + odku2.ExecuteAffrows(); + } + + [Fact] + public void UpdateColumns() + { + g.kingbaseES.Delete(new[] { 300, 301, 302 }).ExecuteAffrows(); + var odku1 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().InsertIdentity()); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(300, 'title-300') +ON CONFLICT(""ID"") DO UPDATE SET +""TITLE"" = EXCLUDED.""TITLE"", +""TIME"" = '2000-01-01 00:00:00.000000'", odku1.ToSql()); + Assert.Equal(1, odku1.ExecuteAffrows()); + + var odku2 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new[] { + new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") } + }).InsertColumns(a => a.title).NoneParameter().InsertIdentity()); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302') +ON CONFLICT(""ID"") DO UPDATE SET +""TITLE"" = EXCLUDED.""TITLE"", +""TIME"" = CASE EXCLUDED.""ID"" +WHEN 300 THEN '2000-01-01 00:00:00.000000' +WHEN 301 THEN '2000-01-01 00:00:00.000000' +WHEN 302 THEN '2000-01-01 00:00:00.000000' END::timestamp", odku2.ToSql()); + odku2.ExecuteAffrows(); + + + g.kingbaseES.Delete(new[] { 300, 301, 302 }).ExecuteAffrows(); + odku1 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }).InsertColumns(a => a.title).NoneParameter().InsertIdentity()).UpdateColumns(a => a.time); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(300, 'title-300') +ON CONFLICT(""ID"") DO UPDATE SET +""TIME"" = '2000-01-01 00:00:00.000000'", odku1.ToSql()); + Assert.Equal(1, odku1.ExecuteAffrows()); + + odku2 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new[] { + new TestOnConflictDoUpdateInfo { id = 300, title = "title-300", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 301, title = "title-301", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 302, title = "title-302", time = DateTime.Parse("2000-01-01") } + }).InsertColumns(a => a.title).NoneParameter().InsertIdentity()).UpdateColumns(a => a.time); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"") VALUES(300, 'title-300'), (301, 'title-301'), (302, 'title-302') +ON CONFLICT(""ID"") DO UPDATE SET +""TIME"" = CASE EXCLUDED.""ID"" +WHEN 300 THEN '2000-01-01 00:00:00.000000' +WHEN 301 THEN '2000-01-01 00:00:00.000000' +WHEN 302 THEN '2000-01-01 00:00:00.000000' END::timestamp", odku2.ToSql()); + odku2.ExecuteAffrows(); + } + + [Fact] + public void Set() + { + g.kingbaseES.Delete(new[] { 400, 401, 402 }).ExecuteAffrows(); + var odku1 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }).NoneParameter().InsertIdentity()).Set(a => a.time, DateTime.Parse("2020-1-1")); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"", ""TIME"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000') +ON CONFLICT(""ID"") DO UPDATE SET +""TIME"" = '2020-01-01 00:00:00.000000'", odku1.ToSql()); + Assert.Equal(1, odku1.ExecuteAffrows()); + + var odku2 = new KingbaseESOnConflictDoUpdate(g.kingbaseES.Insert(new[] { + new TestOnConflictDoUpdateInfo { id = 400, title = "title-400", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 401, title = "title-401", time = DateTime.Parse("2000-01-01") }, + new TestOnConflictDoUpdateInfo { id = 402, title = "title-402", time = DateTime.Parse("2000-01-01") } + }).NoneParameter().InsertIdentity()).Set(a => a.time, DateTime.Parse("2020-1-1")); + Assert.Equal(@"INSERT INTO ""TESTONCONFLICTDOUPDATEINFO""(""ID"", ""TITLE"", ""TIME"") VALUES(400, 'title-400', '2000-01-01 00:00:00.000000'), (401, 'title-401', '2000-01-01 00:00:00.000000'), (402, 'title-402', '2000-01-01 00:00:00.000000') +ON CONFLICT(""ID"") DO UPDATE SET +""TIME"" = '2020-01-01 00:00:00.000000'", odku2.ToSql()); + odku2.ExecuteAffrows(); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAdo/KingbaseESAdoTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAdo/KingbaseESAdoTest.cs new file mode 100644 index 00000000..ad9c7cf5 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAdo/KingbaseESAdoTest.cs @@ -0,0 +1,66 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESAdoTest + { + [Fact] + public void Pool() + { + var t1 = g.kingbaseES.Ado.MasterPool.StatisticsFullily; + } + + [Fact] + public void SlavePools() + { + var t2 = g.kingbaseES.Ado.SlavePools.Count; + } + + [Fact] + public void ExecuteReader() + { + + } + [Fact] + public void ExecuteArray() + { + + } + [Fact] + public void ExecuteNonQuery() + { + + } + [Fact] + public void ExecuteScalar() + { + + } + + [Fact] + public void Query() + { + + var t3 = g.kingbaseES.Ado.Query("select * from \"TB_TOPIC\""); + + var t4 = g.kingbaseES.Ado.Query<(int, string, string)>("select * from \"TB_TOPIC\""); + + var t5 = g.kingbaseES.Ado.Query("select * from \"TB_TOPIC\""); + } + + [Fact] + public void QueryMultipline() + { + //var t3 = g.kingbaseES.Ado.Query("select * from \"TB_TOPIC\"; select * from \"TB_TOPIC\"; select * from \"TB_TOPIC\""); + } + + class xxx + { + public int Id { get; set; } + public string Path { get; set; } + public string Title2 { get; set; } + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAopTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAopTest.cs new file mode 100644 index 00000000..abe66863 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESAopTest.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESAopTest + { + + class TestAuditValue + { + public Guid id { get; set; } + [Now] + public DateTime createtime { get; set; } + } + class NowAttribute: Attribute { } + + [Fact] + public void AuditValue() + { + var date = DateTime.Now.Date; + var item = new TestAuditValue(); + + EventHandler audit = (s, e) => + { + if (e.Property.GetCustomAttribute(false) != null) + e.Value = DateTime.Now.Date; + }; + g.kingbaseES.Aop.AuditValue += audit; + + g.kingbaseES.Insert(item).ExecuteAffrows(); + + g.kingbaseES.Aop.AuditValue -= audit; + + Assert.Equal(item.createtime, date); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESCodeFirstTest.cs new file mode 100644 index 00000000..65197cba --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESCodeFirstTest.cs @@ -0,0 +1,334 @@ +using FreeSql.DataAnnotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESCodeFirstTest + { + [Fact] + public void StringLength() + { + var dll = g.kingbaseES.CodeFirst.GetComparisonDDLStatements(); + g.kingbaseES.CodeFirst.SyncStructure(); + } + class TS_SLTB + { + public Guid Id { get; set; } + [Column(StringLength = 50)] + public string Title { get; set; } + + [Column(IsNullable = false, StringLength = 50)] + public string TitleSub { get; set; } + } + + [Fact] + public void ֱ_ֶ() + { + var sql = g.kingbaseES.CodeFirst.GetComparisonDDLStatements<ֱ>(); + g.kingbaseES.CodeFirst.SyncStructure<ֱ>(); + + var item = new ֱ + { + = "Ա", + ʱ = DateTime.Now + }; + Assert.Equal(1, g.kingbaseES.Insert<ֱ>().AppendData(item).ExecuteAffrows()); + Assert.NotEqual(Guid.Empty, item.); + var item2 = g.kingbaseES.Select<ֱ>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + + item. = "Ա"; + Assert.Equal(1, g.kingbaseES.Update<ֱ>().SetSource(item).ExecuteAffrows()); + item2 = g.kingbaseES.Select<ֱ>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + + item. = "Ա_repo"; + var repo = g.kingbaseES.GetRepository<ֱ>(); + Assert.Equal(1, repo.Update(item)); + item2 = g.kingbaseES.Select<ֱ>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + + item. = "Ա_repo22"; + Assert.Equal(1, repo.Update(item)); + item2 = g.kingbaseES.Select<ֱ>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + } + [Table(Name = "123ֱ")] + class ֱ + { + [Column(IsPrimary = true, Name = "123")] + public Guid { get; set; } + + [Column(Name = "123")] + public string { get; set; } + + [Column(Name = "123ʱ")] + public DateTime ʱ { get; set; } + } + + [Fact] + public void ı_ֶ() + { + var sql = g.kingbaseES.CodeFirst.GetComparisonDDLStatements<ı>(); + g.kingbaseES.CodeFirst.SyncStructure<ı>(); + + var item = new ı + { + = "Ա", + ʱ = DateTime.Now + }; + Assert.Equal(1, g.kingbaseES.Insert<ı>().AppendData(item).ExecuteAffrows()); + Assert.NotEqual(Guid.Empty, item.); + var item2 = g.kingbaseES.Select<ı>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + + item. = "Ա"; + Assert.Equal(1, g.kingbaseES.Update<ı>().SetSource(item).ExecuteAffrows()); + item2 = g.kingbaseES.Select<ı>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + + item. = "Ա_repo"; + var repo = g.kingbaseES.GetRepository<ı>(); + Assert.Equal(1, repo.Update(item)); + item2 = g.kingbaseES.Select<ı>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + + item. = "Ա_repo22"; + Assert.Equal(1, repo.Update(item)); + item2 = g.kingbaseES.Select<ı>().Where(a => a. == item.).First(); + Assert.NotNull(item2); + Assert.Equal(item., item2.); + Assert.Equal(item., item2.); + } + class ı + { + [Column(IsPrimary = true)] + public Guid { get; set; } + + public string { get; set; } + + public DateTime ʱ { get; set; } + } + + [Fact] + public void AddUniques() + { + var sql = g.kingbaseES.CodeFirst.GetComparisonDDLStatements(); + g.kingbaseES.CodeFirst.SyncStructure(); + g.kingbaseES.CodeFirst.SyncStructure(typeof(AddUniquesInfo), "AddUniquesInfo1"); + } + [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("{tablename}_uk_phone", "phone", true)] + [Index("{tablename}_uk_group_index", "group,index", true)] + [Index("{tablename}_uk_group_index22", "group, index22", true)] + class AddUniquesInfo + { + public Guid id { get; set; } + public string phone { get; set; } + + public string group { get; set; } + public int index { get; set; } + public string index22 { get; set; } + } + [Fact] + public void AddField() + { + var sql = g.kingbaseES.CodeFirst.GetComparisonDDLStatements(); + + var id = g.kingbaseES.Insert().AppendData(new TopicAddField { }).ExecuteIdentity(); + + //var inserted = g.kingbaseES.Insert().AppendData(new TopicAddField { }).ExecuteInserted(); + } + + [Table(Name = "TopicAddField", OldName = "xxxtb.TopicAddField")] + public class TopicAddField + { + [Column(IsIdentity = true)] + public int Id { get; set; } + + public string name { get; set; } + + [Column(DbType = "varchar2(200) not null", OldName = "title")] + public string title2 { get; set; } = "10"; + + [Column(IsIgnore = true)] + public DateTime ct { get; set; } = DateTime.Now; + } + + [Fact] + public void GetComparisonDDLStatements() + { + var sql = g.kingbaseES.CodeFirst.GetComparisonDDLStatements(); + Assert.True(string.IsNullOrEmpty(sql)); //κ + //sql = g.kingbaseES.CodeFirst.GetComparisonDDLStatements(); + } + + IInsert insert => g.kingbaseES.Insert(); + ISelect select => g.kingbaseES.Select(); + + [Fact] + public void CurdAllField() + { + var item = new TableAllType { }; + item.Id = (int)insert.AppendData(item).ExecuteIdentity(); + + var newitem = select.Where(a => a.Id == item.Id).ToOne(); + + var item2 = new TableAllType + { + Bool = true, + BoolNullable = true, + Byte = 255, + ByteNullable = 127, + Bytes = Encoding.UTF8.GetBytes("й"), + DateTime = DateTime.Now, + DateTimeNullable = DateTime.Now.AddHours(-1), + Decimal = 99.99M, + DecimalNullable = 99.98M, + Double = 999.99, + DoubleNullable = 999.98, + Enum1 = TableAllTypeEnumType1.e5, + Enum1Nullable = TableAllTypeEnumType1.e3, + Enum2 = TableAllTypeEnumType2.f2, + Enum2Nullable = TableAllTypeEnumType2.f3, + Float = 19.99F, + FloatNullable = 19.98F, + Guid = Guid.NewGuid(), + GuidNullable = Guid.NewGuid(), + Int = int.MaxValue, + IntNullable = int.MinValue, + SByte = 100, + SByteNullable = 99, + Short = short.MaxValue, + ShortNullable = short.MinValue, + String = "йstring'\\?!@#$%^&*()_+{}}{~?><<>", + Char = 'X', + TimeSpan = TimeSpan.FromSeconds(999), + TimeSpanNullable = TimeSpan.FromSeconds(60), + UInt = uint.MaxValue, + UIntNullable = uint.MinValue, + ULong = ulong.MaxValue, + ULongNullable = ulong.MinValue, + UShort = ushort.MaxValue, + UShortNullable = ushort.MinValue, + testFielLongNullable = long.MinValue + }; + var sqlPar = insert.AppendData(item2).ToSql(); + var sqlText = insert.AppendData(item2).NoneParameter().ToSql(); + var item3NP = insert.AppendData(item2).NoneParameter().ExecuteIdentity(); + + item2.Id = (int)insert.AppendData(item2).ExecuteIdentity(); + var newitem21 = select.Where(a => a.Id == item2.Id).First(a => new + { + a.Id, + a.id2, + a.SByte, + a.Short, + a.Int, + a.Long, + a.Byte, + a.UShort, + a.UInt, + a.ULong, + a.Double, + a.Float, + a.Decimal, + a.TimeSpan, + a.DateTimeOffSet, + a.Bytes, + a.String, + a.Char, + a.Guid + }); + var newitem22 = select.Where(a => a.Id == item2.Id).First(a => new + { + a.Id, a.id2, a.SByte, a.Short, a.Int, a.Long, a.Byte, a.UShort, a.UInt, a.ULong, a.Double, a.Float, a.Decimal, a.TimeSpan, a.DateTime, a.DateTimeOffSet, a.Bytes, a.String, a.Char, a.Guid + }); + + var newitem2 = select.Where(a => a.Id == item2.Id).ToOne(); + Assert.Equal(item2.String, newitem2.String); + Assert.Equal(item2.Char, newitem2.Char); + + item2.Id = (int)insert.NoneParameter().AppendData(item2).ExecuteIdentity(); + newitem2 = select.Where(a => a.Id == item2.Id).ToOne(); + Assert.Equal(item2.String, newitem2.String); + Assert.Equal(item2.Char, newitem2.Char); + + var items = select.ToList(); + var itemstb = select.ToDataTable(); + } + + [Table(Name = "tb_alltype")] + class TableAllType + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + + public string id2 { get; set; } = "id2=10"; + + public bool Bool { get; set; } + public sbyte SByte { get; set; } + public short Short { get; set; } + public int Int { get; set; } + public long Long { get; set; } + public byte Byte { get; set; } + public ushort UShort { get; set; } + public uint UInt { get; set; } + public ulong ULong { get; set; } + public double Double { get; set; } + public float Float { get; set; } + public decimal Decimal { get; set; } + public TimeSpan TimeSpan { get; set; } + public DateTime DateTime { get; set; } + public DateTime DateTimeOffSet { get; set; } + public byte[] Bytes { get; set; } + public string String { get; set; } + public char Char { get; set; } + public Guid Guid { get; set; } + + public bool? BoolNullable { get; set; } + public sbyte? SByteNullable { get; set; } + public short? ShortNullable { get; set; } + public int? IntNullable { get; set; } + public long? testFielLongNullable { get; set; } + public byte? ByteNullable { get; set; } + public ushort? UShortNullable { get; set; } + public uint? UIntNullable { get; set; } + public ulong? ULongNullable { get; set; } + public double? DoubleNullable { get; set; } + public float? FloatNullable { get; set; } + public decimal? DecimalNullable { get; set; } + public TimeSpan? TimeSpanNullable { get; set; } + public DateTime? DateTimeNullable { get; set; } + public DateTime? DateTimeOffSetNullable { get; set; } + public Guid? GuidNullable { get; set; } + + public TableAllTypeEnumType1 Enum1 { get; set; } + public TableAllTypeEnumType1? Enum1Nullable { get; set; } + public TableAllTypeEnumType2 Enum2 { get; set; } + public TableAllTypeEnumType2? Enum2Nullable { get; set; } + } + + public enum TableAllTypeEnumType1 { e1, e2, e3, e5 } + [Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESDbFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESDbFirstTest.cs new file mode 100644 index 00000000..d4fa8964 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESDbFirstTest.cs @@ -0,0 +1,64 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.KingbaseES +{ + public class KingbaseESDbFirstTest + { + [Fact] + public void GetDatabases() + { + var t1 = g.kingbaseES.DbFirst.GetDatabases(); + } + + [Fact] + public void GetTablesByDatabase() + { + var t2 = g.kingbaseES.DbFirst.GetTablesByDatabase(); + Assert.True(t2.Count > 0); + } + + [Fact] + public void GetTableByName() + { + var fsql = g.kingbaseES; + var t1 = fsql.DbFirst.GetTableByName("tb_alltype"); + var t2 = fsql.DbFirst.GetTableByName("public.tb_alltype"); + Assert.NotNull(t1); + Assert.NotNull(t2); + Assert.True(t1.Columns.Count > 0); + Assert.True(t2.Columns.Count > 0); + Assert.Equal(t1.Columns.Count, t2.Columns.Count); + var t3 = fsql.DbFirst.GetTableByName("notexists_tb"); + Assert.Null(t3); + } + + [Fact] + public void ExistsTable() + { + var fsql = g.kingbaseES; + Assert.False(fsql.DbFirst.ExistsTable("test_existstb01")); + Assert.False(fsql.DbFirst.ExistsTable("public.test_existstb01")); + Assert.False(fsql.DbFirst.ExistsTable("test_existstb01", false)); + Assert.False(fsql.DbFirst.ExistsTable("public.test_existstb01", false)); + fsql.CodeFirst.SyncStructure(typeof(test_existstb01)); + Assert.True(fsql.DbFirst.ExistsTable("test_existstb01")); + Assert.True(fsql.DbFirst.ExistsTable("public.test_existstb01")); + Assert.False(fsql.DbFirst.ExistsTable("Test_existstb01", false)); + Assert.False(fsql.DbFirst.ExistsTable("public.Test_existstb01", false)); + fsql.Ado.ExecuteNonQuery("drop table test_existstb01"); + + Assert.False(fsql.DbFirst.ExistsTable("tbexts.test_existstb01")); + Assert.False(fsql.DbFirst.ExistsTable("tbexts.test_existstb01", false)); + fsql.CodeFirst.SyncStructure(typeof(test_existstb01), "tbexts.test_existstb01"); + Assert.True(fsql.DbFirst.ExistsTable("tbexts.test_existstb01")); + Assert.False(fsql.DbFirst.ExistsTable("tbexts.Test_existstb01", false)); + fsql.Ado.ExecuteNonQuery("drop table \"TBEXTS\".test_existstb01"); + } + class test_existstb01 + { + public Guid id { get; set; } + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/ConvertTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/ConvertTest.cs new file mode 100644 index 00000000..6c36c3cb --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/ConvertTest.cs @@ -0,0 +1,169 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseESExpression +{ + public class ConvertTest + { + + ISelect select => g.kingbaseES.Select(); + + [Table(Name = "tb_topic")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo + { + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo + { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + + [Fact] + public void ToBoolean() + { + var data = new List(); + //data.Add(select.Where(a => (Convert.ToBoolean(a.Clicks) ? 1 : 0) > 0).ToList()); + //data.Add(select.Where(a => (bool.Parse(a.Clicks.ToString()) ? 1 : 0) > 0).ToList()); + } + [Fact] + public void ToByte() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToByte(a.Clicks % 255) > 0).ToList()); + data.Add(select.Where(a => byte.Parse((a.Clicks % 255).ToString()) > 0).ToList()); + } + [Fact] + public void ToChar() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToChar(a.Clicks) == '1').ToList()); + data.Add(select.Where(a => char.Parse(a.Clicks.ToString()) == '1').ToList()); + } + [Fact] + public void ToDateTime() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToDateTime(a.CreateTime.ToString()).Year > 0).ToList()); + data.Add(select.Where(a => DateTime.Parse(a.CreateTime.ToString()).Year > 0).ToList()); + } + [Fact] + public void ToDecimal() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToDecimal(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => decimal.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToDouble() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToDouble(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => double.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToInt16() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToInt16(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => short.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToInt32() + { + var data = new List(); + data.Add(select.Where(a => (int)a.Clicks > 0).ToList()); + data.Add(select.Where(a => Convert.ToInt32(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => int.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToInt64() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToInt64(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => long.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToSByte() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToSByte(a.Clicks % 128) > 0).ToList()); + data.Add(select.Where(a => sbyte.Parse((a.Clicks % 128).ToString()) > 0).ToList()); + } + [Fact] + public void ToSingle() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToSingle(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => float.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void this_ToString() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToString(a.Clicks).Equals("")).ToList()); + data.Add(select.Where(a => a.Clicks.ToString().Equals("")).ToList()); + } + [Fact] + public void ToUInt16() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToUInt16(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => ushort.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToUInt32() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToUInt32(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => uint.Parse(a.Clicks.ToString()) > 0).ToList()); + } + [Fact] + public void ToUInt64() + { + var data = new List(); + data.Add(select.Where(a => Convert.ToUInt64(a.Clicks) > 0).ToList()); + data.Add(select.Where(a => ulong.Parse(a.Clicks.ToString()) > 0).ToList()); + } + + [Fact] + public void Guid_Parse() + { + var data = new List(); + data.Add(select.Where(a => Guid.Parse(Guid.Empty.ToString()) == Guid.Empty).ToList()); + } + + [Fact] + public void Guid_NewGuid() + { + var data = new List(); + //data.Add(select.OrderBy(a => Guid.NewGuid()).Limit(10).ToList()); + } + + [Fact] + public void Random() + { + var data = new List(); + data.Add(select.Where(a => new Random().Next() > a.Clicks).Limit(10).ToList()); + data.Add(select.Where(a => new Random().NextDouble() > a.Clicks).Limit(10).ToList()); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/DateTimeTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/DateTimeTest.cs new file mode 100644 index 00000000..5181c96a --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/DateTimeTest.cs @@ -0,0 +1,732 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseESExpression +{ + public class DateTimeTest + { + + ISelect select => g.kingbaseES.Select(); + + [Table(Name = "tb_topic111333")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } = DateTime.Now; + } + [Table(Name = "TestTypeInfo333")] + class TestTypeInfo + { + [Column(IsIdentity = true)] + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + public DateTime Time { get; set; } = DateTime.Now; + } + [Table(Name = "TestTypeParentInf1")] + class TestTypeParentInfo + { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + public DateTime Time2 { get; set; } = DateTime.Now; + } + + [Fact] + public void this_ToString() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.ToString().Equals(DateTime.Now.ToString())).ToList()); + data.Add(select.Where(a => a.Type.Time.AddYears(1).ToString().Equals(DateTime.Now.ToString())).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddYears(1).ToString().Equals(DateTime.Now.ToString())).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((date_format(a.`CreateTime`, '%Y-%m-%d %H:%i:%s.%f') = now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((date_format(date_add(a__Type.`Time`, interval (1) year), '%Y-%m-%d %H:%i:%s.%f') = now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((date_format(date_add(a__Type__Parent.`Time2`, interval (1) year), '%Y-%m-%d %H:%i:%s.%f') = now())) + + g.kingbaseES.Insert(new Topic()).ExecuteAffrows(); + var dtn = DateTime.Parse("2020-1-1 0:0:0"); + var dts = Enumerable.Range(1, 12).Select(a => dtn.AddMonths(a)) + .Concat(Enumerable.Range(1, 31).Select(a => dtn.AddDays(a))) + .Concat(Enumerable.Range(1, 24).Select(a => dtn.AddHours(a))) + .Concat(Enumerable.Range(1, 60).Select(a => dtn.AddMinutes(a))) + .Concat(Enumerable.Range(1, 60).Select(a => dtn.AddSeconds(a))); + foreach (var dt in dts) + { + Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), select.First(a => dt.ToString())); + Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm:ss"), select.First(a => dt.ToString("yyyy-MM-dd HH:mm:ss"))); + Assert.Equal(dt.ToString("yyyy-MM-dd HH:mm"), select.First(a => dt.ToString("yyyy-MM-dd HH:mm"))); + Assert.Equal(dt.ToString("yyyy-MM-dd HH"), select.First(a => dt.ToString("yyyy-MM-dd HH"))); + Assert.Equal(dt.ToString("yyyy-MM-dd"), select.First(a => dt.ToString("yyyy-MM-dd"))); + Assert.Equal(dt.ToString("yyyy-MM"), select.First(a => dt.ToString("yyyy-MM"))); + Assert.Equal(dt.ToString("yyyyMMddHHmmss"), select.First(a => dt.ToString("yyyyMMddHHmmss"))); + Assert.Equal(dt.ToString("yyyyMMddHHmm"), select.First(a => dt.ToString("yyyyMMddHHmm"))); + Assert.Equal(dt.ToString("yyyyMMddHH"), select.First(a => dt.ToString("yyyyMMddHH"))); + Assert.Equal(dt.ToString("yyyyMMdd"), select.First(a => dt.ToString("yyyyMMdd"))); + Assert.Equal(dt.ToString("yyyyMM"), select.First(a => dt.ToString("yyyyMM"))); + Assert.Equal(dt.ToString("yyyy"), select.First(a => dt.ToString("yyyy"))); + Assert.Equal(dt.ToString("HH:mm:ss"), select.First(a => dt.ToString("HH:mm:ss"))); + Assert.Equal(dt.ToString("yyyy MM dd HH mm ss yy M d H hh h"), select.First(a => dt.ToString("yyyy MM dd HH mm ss yy M d H hh h"))); + Assert.Equal(dt.ToString("yyyy MM dd HH mm ss yy M d H hh h m s"), select.First(a => dt.ToString("yyyy MM dd HH mm ss yy M d H hh h m s"))); + } + } + [Fact] + public void Now() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Date == DateTime.Now.Date).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (cast(date_format(a.`CreateTime`, '%Y-%m-%d') as datetime) = cast(date_format(now(), '%Y-%m-%d') as datetime)) + } + [Fact] + public void UtcNow() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Date == DateTime.UtcNow.Date).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (cast(date_format(a.`CreateTime`, '%Y-%m-%d') as datetime) = cast(date_format(utc_timestamp(), '%Y-%m-%d') as datetime)) + } + [Fact] + public void MinValue() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Date == DateTime.MinValue.Date).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (cast(date_format(a.`CreateTime`, '%Y-%m-%d') as datetime) = cast(date_format(cast('0001/1/1 0:00:00' as datetime), '%Y-%m-%d') as datetime)) + } + [Fact] + public void MaxValue() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Date == DateTime.MaxValue.Date).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (cast(date_format(a.`CreateTime`, '%Y-%m-%d') as datetime) = cast(date_format(cast('9999/12/31 23:59:59' as datetime), '%Y-%m-%d') as datetime)) + } + [Fact] + public void Date() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Date == DateTime.Now.Date).ToList()); + //data.Add(select.Where(a => a.Type.Time.Date > DateTime.Now.Date).ToList()); + //data.Add(select.Where(a => a.Type.Parent.Time2.Date > DateTime.Now.Date).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (cast(date_format(a.`CreateTime`, '%Y-%m-%d') as datetime) = cast(date_format(now(), '%Y-%m-%d') as datetime)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (cast(date_format(a__Type.`Time`, '%Y-%m-%d') as datetime) > cast(date_format(now(), '%Y-%m-%d') as datetime)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (cast(date_format(a__Type__Parent.`Time2`, '%Y-%m-%d') as datetime) > cast(date_format(now(), '%Y-%m-%d') as datetime)); + //data.Add(select.Where(a => DateTime.Now.Subtract(a.CreateTime.Date).TotalSeconds > 0).ToList()); + //data.Add(select.Where(a => DateTime.Now.Subtract(a.Type.Time.Date).TotalSeconds > 0).ToList()); + //data.Add(select.Where(a => DateTime.Now.Subtract(a.Type.Parent.Time2.Date).TotalSeconds > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (((timestampdiff(microsecond, cast(date_format(a.`CreateTime`, '%Y-%m-%d') as datetime), now())) / 1000000) > 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (((timestampdiff(microsecond, cast(date_format(a__Type.`Time`, '%Y-%m-%d') as datetime), now())) / 1000000) > 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (((timestampdiff(microsecond, cast(date_format(a__Type__Parent.`Time2`, '%Y-%m-%d') as datetime), now())) / 1000000) > 0) + } + [Fact] + public void TimeOfDay() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay == DateTime.Now.TimeOfDay).ToList()); + data.Add(select.Where(a => a.Type.Time.TimeOfDay > DateTime.Now.TimeOfDay).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.TimeOfDay > DateTime.Now.TimeOfDay).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (timestampdiff(microsecond, date_format(now(), '1970-1-1 %H:%i:%s.%f'), now()) + 62135596800000000)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((timestampdiff(microsecond, date_format(a__Type.`Time`, '1970-1-1 %H:%i:%s.%f'), a__Type.`Time`) + 62135596800000000) > (timestampdiff(microsecond, date_format(now(), '1970-1-1 %H:%i:%s.%f'), now()) + 62135596800000000)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((timestampdiff(microsecond, date_format(a__Type__Parent.`Time2`, '1970-1-1 %H:%i:%s.%f'), a__Type__Parent.`Time2`) + 62135596800000000) > (timestampdiff(microsecond, date_format(now(), '1970-1-1 %H:%i:%s.%f'), now()) + 62135596800000000)) + } + [Fact] + public void DayOfWeek() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.DayOfWeek > DateTime.Now.DayOfWeek).ToList()); + data.Add(select.Where(a => a.Type.Time.DayOfWeek > DateTime.Now.DayOfWeek).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.DayOfWeek > DateTime.Now.DayOfWeek).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((dayofweek(a.`CreateTime`) - 1) > (dayofweek(now()) - 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((dayofweek(a__Type.`Time`) - 1) > (dayofweek(now()) - 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((dayofweek(a__Type__Parent.`Time2`) - 1) > (dayofweek(now()) - 1)) + } + [Fact] + public void Day() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Day > DateTime.Now.Day).ToList()); + data.Add(select.Where(a => a.Type.Time.Day > DateTime.Now.Day).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Day > DateTime.Now.Day).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (dayofmonth(a.`CreateTime`) > dayofmonth(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (dayofmonth(a__Type.`Time`) > dayofmonth(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (dayofmonth(a__Type__Parent.`Time2`) > dayofmonth(now())) + } + [Fact] + public void DayOfYear() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.DayOfYear > DateTime.Now.DayOfYear).ToList()); + data.Add(select.Where(a => a.Type.Time.DayOfYear > DateTime.Now.DayOfYear).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.DayOfYear > DateTime.Now.DayOfYear).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (dayofyear(a.`CreateTime`) > dayofyear(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (dayofyear(a__Type.`Time`) > dayofyear(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (dayofyear(a__Type__Parent.`Time2`) > dayofyear(now())) + } + [Fact] + public void Month() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Month > DateTime.Now.Month).ToList()); + data.Add(select.Where(a => a.Type.Time.Month > DateTime.Now.Month).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Month > DateTime.Now.Month).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (month(a.`CreateTime`) > month(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (month(a__Type.`Time`) > month(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (month(a__Type__Parent.`Time2`) > month(now())) + } + [Fact] + public void Year() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Year > DateTime.Now.Year).ToList()); + data.Add(select.Where(a => a.Type.Time.Year > DateTime.Now.Year).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Year > DateTime.Now.Year).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (year(a.`CreateTime`) > year(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (year(a__Type.`Time`) > year(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (year(a__Type__Parent.`Time2`) > year(now())) + } + [Fact] + public void Hour() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Hour > DateTime.Now.Hour).ToList()); + data.Add(select.Where(a => a.Type.Time.Hour > DateTime.Now.Hour).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Hour > DateTime.Now.Hour).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (hour(a.`CreateTime`) > hour(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (hour(a__Type.`Time`) > hour(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (hour(a__Type__Parent.`Time2`) > hour(now())) + } + [Fact] + public void Minute() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Minute > DateTime.Now.Minute).ToList()); + data.Add(select.Where(a => a.Type.Time.Minute > DateTime.Now.Minute).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Minute > DateTime.Now.Minute).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (minute(a.`CreateTime`) > minute(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (minute(a__Type.`Time`) > minute(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (minute(a__Type__Parent.`Time2`) > minute(now())) + } + [Fact] + public void Second() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Second > DateTime.Now.Second).ToList()); + data.Add(select.Where(a => a.Type.Time.Second > DateTime.Now.Second).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Second > DateTime.Now.Second).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (second(a.`CreateTime`) > second(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (second(a__Type.`Time`) > second(now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (second(a__Type__Parent.`Time2`) > second(now())) + } + [Fact] + public void Millisecond() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Millisecond > DateTime.Now.Millisecond).ToList()); + data.Add(select.Where(a => a.Type.Time.Millisecond > DateTime.Now.Millisecond).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Millisecond > DateTime.Now.Millisecond).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (floor(microsecond(a.`CreateTime`) / 1000) > floor(microsecond(now()) / 1000)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (floor(microsecond(a__Type.`Time`) / 1000) > floor(microsecond(now()) / 1000)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (floor(microsecond(a__Type__Parent.`Time2`) / 1000) > floor(microsecond(now()) / 1000)) + } + [Fact] + public void Ticks() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Ticks > DateTime.Now.Ticks).ToList()); + data.Add(select.Where(a => a.Type.Time.Ticks > DateTime.Now.Ticks).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Ticks > DateTime.Now.Ticks).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((timestampdiff(microsecond, '1970-1-1', a.`CreateTime`) * 10 + 621355968000000000) > (timestampdiff(microsecond, '1970-1-1', now()) * 10 + 621355968000000000)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((timestampdiff(microsecond, '1970-1-1', a__Type.`Time`) * 10 + 621355968000000000) > (timestampdiff(microsecond, '1970-1-1', now()) * 10 + 621355968000000000)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((timestampdiff(microsecond, '1970-1-1', a__Type__Parent.`Time2`) * 10 + 621355968000000000) > (timestampdiff(microsecond, '1970-1-1', now()) * 10 + 621355968000000000)) + } + [Fact] + public void Add() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.Add(TimeSpan.FromDays(1)) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.Add(TimeSpan.FromDays(1)) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.Add(TimeSpan.FromDays(1)) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval ((1 * 86400000000)) microsecond) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval ((1 * 86400000000)) microsecond) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval ((1 * 86400000000)) microsecond) > now()) + } + [Fact] + public void AddDays() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddDays(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddDays(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddDays(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) day) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) day) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) day) > now()) + } + [Fact] + public void AddHours() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddHours(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddHours(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddHours(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) hour) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) hour) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) hour) > now()) + } + [Fact] + public void AddMilliseconds() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddMilliseconds(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddMilliseconds(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddMilliseconds(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) * 1000 microsecond) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) * 1000 microsecond) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) * 1000 microsecond) > now()) + } + [Fact] + public void AddMinutes() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddMinutes(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddMinutes(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddMinutes(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) minute) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) minute) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) minute) > now()) + } + [Fact] + public void AddMonths() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddMonths(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddMonths(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddMonths(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) month) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) month) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) month) > now()) + } + [Fact] + public void AddSeconds() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddSeconds(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddSeconds(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddSeconds(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) second) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) second) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) second) > now()) + } + [Fact] + public void AddTicks() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddTicks(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddTicks(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddTicks(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) / 10 microsecond) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) / 10 microsecond) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) / 10 microsecond) > now()) + } + [Fact] + public void AddYears() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddYears(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Time.AddYears(1) > DateTime.Now).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddYears(1) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (date_add(a.`CreateTime`, interval (1) year) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (date_add(a__Type.`Time`, interval (1) year) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (date_add(a__Type__Parent.`Time2`, interval (1) year) > now()) + } + [Fact] + public void Subtract() + { + var data = new List(); + //data.Add(select.Where(a => a.CreateTime.Subtract(DateTime.Now).TotalSeconds > 0).ToList()); + //data.Add(select.Where(a => a.Type.Time.Subtract(DateTime.Now).TotalSeconds > 0).ToList()); + //data.Add(select.Where(a => a.Type.Parent.Time2.Subtract(DateTime.Now).TotalSeconds > 0).ToList()); + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //WHERE ((extract(day from (systimestamp-a."CREATETIME"))*86400+extract(hour from (systimestamp-a."CREATETIME"))*3600+extract(minute from (systimestamp-a."CREATETIME"))*60+extract(second from (systimestamp-a."CREATETIME"))) > 0) + + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //WHERE ((extract(day from (systimestamp-a__Type."TIME"))*86400+extract(hour from (systimestamp-a__Type."TIME"))*3600+extract(minute from (systimestamp-a__Type."TIME"))*60+extract(second from (systimestamp-a__Type."TIME"))) > 0) + + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //LEFT JOIN "TESTTYPEPARENTINF1" a__Type__Parent ON a__Type__Parent."ID" = a__Type."PARENTID" + //WHERE ((extract(day from (systimestamp-a__Type__Parent."TIME2"))*86400+extract(hour from (systimestamp-a__Type__Parent."TIME2"))*3600+extract(minute from (systimestamp-a__Type__Parent."TIME2"))*60+extract(second from (systimestamp-a__Type__Parent."TIME2"))) > 0) + //data.Add(select.Where(a => a.CreateTime.Subtract(TimeSpan.FromDays(1)) > a.CreateTime).ToList()); + //data.Add(select.Where(a => a.Type.Time.Subtract(TimeSpan.FromDays(1)) > a.CreateTime).ToList()); + //data.Add(select.Where(a => a.Type.Parent.Time2.Subtract(TimeSpan.FromDays(1)) > a.CreateTime).ToList()); + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //WHERE ((a."CREATETIME"-numtodsinterval((1)*86400,'second')) > a."CREATETIME") + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //WHERE ((a__Type."TIME"-numtodsinterval((1)*86400,'second')) > a."CREATETIME") + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //LEFT JOIN "TESTTYPEPARENTINF1" a__Type__Parent ON a__Type__Parent."ID" = a__Type."PARENTID" + //WHERE ((a__Type__Parent."TIME2"-numtodsinterval((1)*86400,'second')) > a."CREATETIME") + } + [Fact] + public void _ЧͬSubtract() + { + var data = new List(); + //data.Add(select.Where(a => (a.CreateTime - DateTime.Now).TotalSeconds > 0).ToList()); + //data.Add(select.Where(a => (a.Type.Time - DateTime.Now).TotalSeconds > 0).ToList()); + //data.Add(select.Where(a => (a.Type.Parent.Time2 - DateTime.Now).TotalSeconds > 0).ToList()); + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //WHERE ((extract(day from (systimestamp-a."CREATETIME"))*86400+extract(hour from (systimestamp-a."CREATETIME"))*3600+extract(minute from (systimestamp-a."CREATETIME"))*60+extract(second from (systimestamp-a."CREATETIME"))) > 0) + + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //WHERE ((extract(day from (systimestamp-a__Type."TIME"))*86400+extract(hour from (systimestamp-a__Type."TIME"))*3600+extract(minute from (systimestamp-a__Type."TIME"))*60+extract(second from (systimestamp-a__Type."TIME"))) > 0) + + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //LEFT JOIN "TESTTYPEPARENTINF1" a__Type__Parent ON a__Type__Parent."ID" = a__Type."PARENTID" + //WHERE ((extract(day from (systimestamp-a__Type__Parent."TIME2"))*86400+extract(hour from (systimestamp-a__Type__Parent."TIME2"))*3600+extract(minute from (systimestamp-a__Type__Parent."TIME2"))*60+extract(second from (systimestamp-a__Type__Parent."TIME2"))) > 0) + //data.Add(select.Where(a => (a.CreateTime - TimeSpan.FromDays(1)) > a.CreateTime).ToList()); + //data.Add(select.Where(a => (a.Type.Time - TimeSpan.FromDays(1)) > a.CreateTime).ToList()); + //data.Add(select.Where(a => (a.Type.Parent.Time2 - TimeSpan.FromDays(1)) > a.CreateTime).ToList()); + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a."TITLE", a."CREATETIME" + //FROM "TB_TOPIC111333" a + //WHERE ((a."CREATETIME"-numtodsinterval((1)*86400,'second')) > a."CREATETIME") + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //WHERE ((a__Type."TIME"-numtodsinterval((1)*86400,'second')) > a."CREATETIME") + //SELECT a."ID", a."CLICKS", a."TYPEGUID", a__Type."GUID", a__Type."PARENTID", a__Type."NAME", a__Type."TIME", a."TITLE", a."CREATETIME" + + //FROM "TB_TOPIC111333" a + //LEFT JOIN "TESTTYPEINFO333" a__Type ON a__Type."GUID" = a."TYPEGUID" + //LEFT JOIN "TESTTYPEPARENTINF1" a__Type__Parent ON a__Type__Parent."ID" = a__Type."PARENTID" + //WHERE ((a__Type__Parent."TIME2"-numtodsinterval((1)*86400,'second')) > a."CREATETIME") + } + [Fact] + public void this_Equals() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.AddYears(1).Equals(DateTime.Now)).ToList()); + data.Add(select.Where(a => a.Type.Time.AddYears(1).Equals(DateTime.Now)).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddYears(1).Equals(DateTime.Now)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((date_add(a.`CreateTime`, interval (1) year) = now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((date_add(a__Type.`Time`, interval (1) year) = now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((date_add(a__Type__Parent.`Time2`, interval (1) year) = now())) + } + [Fact] + public void DateTime_Compare() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.CompareTo(DateTime.Now) == 0).ToList()); + data.Add(select.Where(a => a.Type.Time.AddYears(1).CompareTo(DateTime.Now) == 0).ToList()); + data.Add(select.Where(a => a.Type.Parent.Time2.AddYears(1).CompareTo(DateTime.Now) == 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (((a.`CreateTime`) - (now())) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (((date_add(a__Type.`Time`, interval (1) year)) - (now())) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (((date_add(a__Type__Parent.`Time2`, interval (1) year)) - (now())) = 0) + } + [Fact] + public void DateTime_DaysInMonth() + { + var data = new List(); + data.Add(select.Where(a => DateTime.DaysInMonth(a.CreateTime.Year, a.CreateTime.Month) > 30).ToList()); + //data.Add(select.Where(a => DateTime.DaysInMonth(a.Type.Time.Year, a.Type.Time.Month) > 30).ToList()); + //data.Add(select.Where(a => DateTime.DaysInMonth(a.Type.Parent.Time2.Year, a.Type.Parent.Time2.Month) > 30).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (dayofmonth(last_day(concat(year(a.`CreateTime`), month(a.`CreateTime`), '-01'))) > 30); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (dayofmonth(last_day(concat(year(a__Type.`Time`), month(a__Type.`Time`), '-01'))) > 30); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (dayofmonth(last_day(concat(year(a__Type__Parent.`Time2`), month(a__Type__Parent.`Time2`), '-01'))) > 30) + } + [Fact] + public void DateTime_Equals() + { + var data = new List(); + data.Add(select.Where(a => DateTime.Equals(a.CreateTime.AddYears(1), DateTime.Now)).ToList()); + data.Add(select.Where(a => DateTime.Equals(a.Type.Time.AddYears(1), DateTime.Now)).ToList()); + data.Add(select.Where(a => DateTime.Equals(a.Type.Parent.Time2.AddYears(1), DateTime.Now)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((date_add(a.`CreateTime`, interval (1) year) = now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((date_add(a__Type.`Time`, interval (1) year) = now())); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((date_add(a__Type__Parent.`Time2`, interval (1) year) = now())) + } + [Fact] + public void DateTime_IsLeapYear() + { + var data = new List(); + data.Add(select.Where(a => DateTime.IsLeapYear(a.CreateTime.Year)).ToList()); + data.Add(select.Where(a => DateTime.IsLeapYear(a.Type.Time.AddYears(1).Year)).ToList()); + data.Add(select.Where(a => DateTime.IsLeapYear(a.Type.Parent.Time2.AddYears(1).Year)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (((year(a.`CreateTime`)) % 4 = 0 AND (year(a.`CreateTime`)) % 100 <> 0 OR (year(a.`CreateTime`)) % 400 = 0)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (((year(date_add(a__Type.`Time`, interval (1) year))) % 4 = 0 AND (year(date_add(a__Type.`Time`, interval (1) year))) % 100 <> 0 OR (year(date_add(a__Type.`Time`, interval (1) year))) % 400 = 0)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (((year(date_add(a__Type__Parent.`Time2`, interval (1) year))) % 4 = 0 AND (year(date_add(a__Type__Parent.`Time2`, interval (1) year))) % 100 <> 0 OR (year(date_add(a__Type__Parent.`Time2`, interval (1) year))) % 400 = 0)) + } + [Fact] + public void DateTime_Parse() + { + var data = new List(); + data.Add(select.Where(a => DateTime.Parse(a.CreateTime.ToString()) > DateTime.Now).ToList()); + data.Add(select.Where(a => DateTime.Parse(a.Type.Time.AddYears(1).ToString()) > DateTime.Now).ToList()); + data.Add(select.Where(a => DateTime.Parse(a.Type.Parent.Time2.AddYears(1).ToString()) > DateTime.Now).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE (cast(date_format(a.`CreateTime`, '%Y-%m-%d %H:%i:%s.%f') as datetime) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE (cast(date_format(date_add(a__Type.`Time`, interval (1) year), '%Y-%m-%d %H:%i:%s.%f') as datetime) > now()); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE (cast(date_format(date_add(a__Type__Parent.`Time2`, interval (1) year), '%Y-%m-%d %H:%i:%s.%f') as datetime) > now()) + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/MathTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/MathTest.cs new file mode 100644 index 00000000..58be916d --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/MathTest.cs @@ -0,0 +1,156 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseESExpression +{ + public class MathTest + { + + ISelect select => g.kingbaseES.Select(); + + [Table(Name = "tb_topic")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo + { + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo + { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + + [Fact] + public void PI() + { + var data = new List(); + data.Add(select.Where(a => Math.PI + a.Clicks > 0).ToList()); + } + [Fact] + public void Abs() + { + var data = new List(); + data.Add(select.Where(a => Math.Abs(-a.Clicks) > 0).ToList()); + } + [Fact] + public void Sign() + { + var data = new List(); + data.Add(select.Where(a => Math.Sign(-a.Clicks) > 0).ToList()); + } + [Fact] + public void Floor() + { + var data = new List(); + data.Add(select.Where(a => Math.Floor(a.Clicks + 0.5) == a.Clicks).ToList()); + } + [Fact] + public void Ceiling() + { + var data = new List(); + data.Add(select.Where(a => Math.Ceiling(a.Clicks + 0.5) == a.Clicks + 1).ToList()); + } + [Fact] + public void Round() + { + var data = new List(); + data.Add(select.Where(a => Math.Round(a.Clicks + 0.5) == a.Clicks).ToList()); + data.Add(select.Where(a => Math.Round(a.Clicks + 0.5, 1) > a.Clicks).ToList()); + } + [Fact] + public void Exp() + { + var data = new List(); + data.Add(select.Where(a => Math.Exp(1) == a.Clicks + 1).ToList()); + } + [Fact] + public void Log() + { + var data = new List(); + data.Add(select.Where(a => Math.Log(a.Clicks + 0.5) == a.Clicks + 1).ToList()); + } + [Fact] + public void Log10() + { + var data = new List(); + data.Add(select.Where(a => Math.Log10(a.Clicks + 0.5) == a.Clicks + 1).ToList()); + } + [Fact] + public void Pow() + { + var data = new List(); + data.Add(select.Where(a => Math.Pow(2, a.Clicks % 5) == a.Clicks + 1).ToList()); + } + [Fact] + public void Sqrt() + { + var data = new List(); + data.Add(select.Where(a => Math.Sqrt(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Cos() + { + var data = new List(); + data.Add(select.Where(a => Math.Cos(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Sin() + { + var data = new List(); + data.Add(select.Where(a => Math.Sin(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Tan() + { + var data = new List(); + data.Add(select.Where(a => Math.Tan(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Acos() + { + var data = new List(); + //data.Add(select.Where(a => Math.Acos(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Asin() + { + var data = new List(); + //data.Add(select.Where(a => Math.Asin(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Atan() + { + var data = new List(); + data.Add(select.Where(a => Math.Atan(Math.Pow(2, a.Clicks % 5)) == a.Clicks + 1).ToList()); + } + [Fact] + public void Atan2() + { + var data = new List(); + //data.Add(select.Where(a => Math.Atan2(2, a.Clicks) == a.Clicks + 1).ToList()); + } + [Fact] + public void Truncate() + { + var data = new List(); + data.Add(select.Where(a => Math.Truncate(a.Clicks * 1.0 / 3) == a.Clicks + 1).ToList()); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/OtherTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/OtherTest.cs new file mode 100644 index 00000000..09864b3b --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/OtherTest.cs @@ -0,0 +1,165 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseESExpression +{ + public class OtherTest + { + + ISelect select => g.kingbaseES.Select(); + + public OtherTest() + { + } + + [Fact] + public void Div() + { + var t1 = select.Where(a => a.Int / 3 > 3).Limit(10).ToList(); + var t2 = select.Where(a => a.Long / 3 > 3).Limit(10).ToList(); + var t3 = select.Where(a => a.Short / 3 > 3).Limit(10).ToList(); + + var t4 = select.Where(a => a.Int / 3.0 > 3).Limit(10).ToList(); + var t5 = select.Where(a => a.Long / 3.0 > 3).Limit(10).ToList(); + var t6 = select.Where(a => a.Short / 3.0 > 3).Limit(10).ToList(); + + var t7 = select.Where(a => a.Double / 3 > 3).Limit(10).ToList(); + var t8 = select.Where(a => a.Decimal / 3 > 3).Limit(10).ToList(); + var t9 = select.Where(a => a.Float / 3 > 3).Limit(10).ToList(); + } + + [Fact] + public void Boolean() + { + var t1 = select.Where(a => a.Bool == true).ToList(); + var t2 = select.Where(a => a.Bool != true).ToList(); + var t3 = select.Where(a => a.Bool == false).ToList(); + var t4 = select.Where(a => !a.Bool).ToList(); + var t5 = select.Where(a => a.Bool).ToList(); + var t51 = select.WhereCascade(a => a.Bool).Limit(10).ToList(); + + var t11 = select.Where(a => a.BoolNullable == true).ToList(); + var t22 = select.Where(a => a.BoolNullable != true).ToList(); + var t33 = select.Where(a => a.BoolNullable == false).ToList(); + var t44 = select.Where(a => !a.BoolNullable.Value).ToList(); + var t55 = select.Where(a => a.BoolNullable.Value).ToList(); + + var t111 = select.Where(a => a.Bool == true && a.Id > 0).ToList(); + var t222 = select.Where(a => a.Bool != true && a.Id > 0).ToList(); + var t333 = select.Where(a => a.Bool == false && a.Id > 0).ToList(); + var t444 = select.Where(a => !a.Bool && a.Id > 0).ToList(); + var t555 = select.Where(a => a.Bool && a.Id > 0).ToList(); + + var t1111 = select.Where(a => a.BoolNullable == true && a.Id > 0).ToList(); + var t2222 = select.Where(a => a.BoolNullable != true && a.Id > 0).ToList(); + var t3333 = select.Where(a => a.BoolNullable == false && a.Id > 0).ToList(); + var t4444 = select.Where(a => !a.BoolNullable.Value && a.Id > 0).ToList(); + var t5555 = select.Where(a => a.BoolNullable.Value && a.Id > 0).ToList(); + + var t11111 = select.Where(a => a.Bool == true && a.Id > 0 && a.Bool == true).ToList(); + var t22222 = select.Where(a => a.Bool != true && a.Id > 0 && a.Bool != true).ToList(); + var t33333 = select.Where(a => a.Bool == false && a.Id > 0 && a.Bool == false).ToList(); + var t44444 = select.Where(a => !a.Bool && a.Id > 0 && !a.Bool).ToList(); + var t55555 = select.Where(a => a.Bool && a.Id > 0 && a.Bool).ToList(); + + var t111111 = select.Where(a => a.BoolNullable == true && a.Id > 0 && a.BoolNullable == true).ToList(); + var t222222 = select.Where(a => a.BoolNullable != true && a.Id > 0 && a.BoolNullable != true).ToList(); + var t333333 = select.Where(a => a.BoolNullable == false && a.Id > 0 && a.BoolNullable == false).ToList(); + var t444444 = select.Where(a => !a.BoolNullable.Value && a.Id > 0 && !a.BoolNullable.Value).ToList(); + var t555555 = select.Where(a => a.BoolNullable.Value && a.Id > 0 && a.BoolNullable.Value).ToList(); + } + + [Fact] + public void Array() + { + IEnumerable testlinqlist = new List(new[] { 1, 2, 3 }); + var testlinq = select.Where(a => testlinqlist.Contains(a.Int)).ToList(); + + //in not in + var sql111 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.Int)).ToList(); + //var sql112 = select.Where(a => new[] { 1, 2, 3 }.Contains(a.Int) == false).ToList(); + var sql113 = select.Where(a => !new[] { 1, 2, 3 }.Contains(a.Int)).ToList(); + + var inarray = new[] { 1, 2, 3 }; + var sql1111 = select.Where(a => inarray.Contains(a.Int)).ToList(); + //var sql1122 = select.Where(a => inarray.Contains(a.Int) == false).ToList(); + var sql1133 = select.Where(a => !inarray.Contains(a.Int)).ToList(); + + + //in not in + var sql11111 = select.Where(a => new List() { 1, 2, 3 }.Contains(a.Int)).ToList(); + //var sql11222 = select.Where(a => new List() { 1, 2, 3 }.Contains(a.Int) == false).ToList(); + var sql11333 = select.Where(a => !new List() { 1, 2, 3 }.Contains(a.Int)).ToList(); + + var sql11111a = select.Where(a => new List(new[] { 1, 2, 3 }).Contains(a.Int)).ToList(); + //var sql11222b = select.Where(a => new List(new[] { 1, 2, 3 }).Contains(a.Int) == false).ToList(); + var sql11333c = select.Where(a => !new List(new[] { 1, 2, 3 }).Contains(a.Int)).ToList(); + + var inarray2 = new List() { 1, 2, 3 }; + var sql111111 = select.Where(a => inarray.Contains(a.Int)).ToList(); + //var sql112222 = select.Where(a => inarray.Contains(a.Int) == false).ToList(); + var sql113333 = select.Where(a => !inarray.Contains(a.Int)).ToList(); + + var inarray2n = Enumerable.Range(1, 3333).ToArray(); + var sql1111111 = select.Where(a => inarray2n.Contains(a.Int)).ToList(); + var sql1122222 = select.Where(a => inarray2n.Contains(a.Int) == false).ToList(); + var sql1133333 = select.Where(a => !inarray2n.Contains(a.Int)).ToList(); + } + + [Table(Name = "tb_alltype")] + class TableAllType + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + + public string id2 { get; set; } = "id2=10"; + + public bool Bool { get; set; } + public sbyte SByte { get; set; } + public short Short { get; set; } + public int Int { get; set; } + public long Long { get; set; } + public byte Byte { get; set; } + public ushort UShort { get; set; } + public uint UInt { get; set; } + public ulong ULong { get; set; } + public double Double { get; set; } + public float Float { get; set; } + public decimal Decimal { get; set; } + public TimeSpan TimeSpan { get; set; } + public DateTime DateTime { get; set; } + public DateTime DateTimeOffSet { get; set; } + public byte[] Bytes { get; set; } + public string String { get; set; } + public Guid Guid { get; set; } + + public bool? BoolNullable { get; set; } + public sbyte? SByteNullable { get; set; } + public short? ShortNullable { get; set; } + public int? IntNullable { get; set; } + public long? testFielLongNullable { get; set; } + public byte? ByteNullable { get; set; } + public ushort? UShortNullable { get; set; } + public uint? UIntNullable { get; set; } + public ulong? ULongNullable { get; set; } + public double? DoubleNullable { get; set; } + public float? FloatNullable { get; set; } + public decimal? DecimalNullable { get; set; } + public TimeSpan? TimeSpanNullable { get; set; } + public DateTime? DateTimeNullable { get; set; } + public DateTime? DateTimeOffSetNullable { get; set; } + public Guid? GuidNullable { get; set; } + + public TableAllTypeEnumType1 Enum1 { get; set; } + public TableAllTypeEnumType1? Enum1Nullable { get; set; } + public TableAllTypeEnumType2 Enum2 { get; set; } + public TableAllTypeEnumType2? Enum2Nullable { get; set; } + } + + public enum TableAllTypeEnumType1 { e1, e2, e3, e5 } + [Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/StringTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/StringTest.cs new file mode 100644 index 00000000..084f1cc2 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/StringTest.cs @@ -0,0 +1,816 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseESExpression +{ + public class StringTest + { + + ISelect select => g.kingbaseES.Select(); + + [Table(Name = "tb_topic")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo + { + [Column(IsIdentity = true)] + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo + { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + class TestEqualsGuid + { + public Guid id { get; set; } + } + + [Fact] + public void Equals__() + { + var list = new List(); + list.Add(select.Where(a => a.Title.Equals("aaa")).ToList()); + list.Add(g.kingbaseES.Select().Where(a => a.id.Equals(Guid.Empty)).ToList()); + } + + [Fact] + public void StringJoin() + { + var fsql = g.kingbaseES; + fsql.Delete().Where("1=1").ExecuteAffrows(); + fsql.Insert(new[] { new StringJoin01 { name = "" }, new StringJoin01 { name = "Ϻ" }, new StringJoin01 { name = "" }, }).ExecuteAffrows(); + + var val1 = string.Join(",", fsql.Select().ToList(a => a.name)); + var val2 = fsql.Select().ToList(a => string.Join(",", fsql.Select().As("b").ToList(b => b.name))); + Assert.Equal(val1, val2[0]); + + val1 = string.Join("**", fsql.Select().ToList(a => a.name)); + val2 = fsql.Select().ToList(a => string.Join("**", fsql.Select().As("b").ToList(b => b.name))); + Assert.Equal(val1, val2[0]); + + val1 = string.Join(",", fsql.Select().ToList(a => a.id)); + val2 = fsql.Select().ToList(a => string.Join(",", fsql.Select().As("b").ToList(b => b.id))); + Assert.Equal(val1, val2[0]); + + val1 = string.Join("**", fsql.Select().ToList(a => a.id)); + val2 = fsql.Select().ToList(a => string.Join("**", fsql.Select().As("b").ToList(b => b.id))); + Assert.Equal(val1, val2[0]); + } + class StringJoin01 + { + [Column(IsIdentity = true)] + public int id { get; set; } + public string name { get; set; } + } + + [Fact] + public void First() + { + Assert.Equal('x', select.First(a => "x1".First())); + Assert.Equal('z', select.First(a => "z1".First())); + } + [Fact] + public void FirstOrDefault() + { + Assert.Equal('x', select.First(a => "x1".FirstOrDefault())); + Assert.Equal('z', select.First(a => "z1".FirstOrDefault())); + } + + [Fact] + public void Format() + { + var item = g.kingbaseES.GetRepository().Insert(new Topic { Clicks = 101, Title = "й101", CreateTime = DateTime.Parse("2020-7-5") }); + var sql = select.WhereDynamic(item).ToSql(a => new + { + str = $"x{a.Id + 1}z-{a.CreateTime.ToString("yyyyMM")}{a.Title}", + str2 = string.Format("{0}x{0}z-{1}{2}", a.Id + 1, a.CreateTime.ToString("yyyyMM"), a.Title) + }); + Assert.Equal($@"SELECT 'x'||coalesce(((a.""ID"" + 1))::text, '')||'z-'||coalesce(to_char((a.""CREATETIME"")::timestamp,'YYYYMM'), '')||''||coalesce(a.""TITLE"", '')||'' as1, ''||coalesce(((a.""ID"" + 1))::text, '')||'x'||coalesce(((a.""ID"" + 1))::text, '')||'z-'||coalesce(to_char((a.""CREATETIME"")::timestamp,'YYYYMM'), '')||''||coalesce(a.""TITLE"", '')||'' as2 +FROM ""TB_TOPIC"" a +WHERE (a.""ID"" = {item.Id})", sql); + + var item2 = select.WhereDynamic(item).First(a => new + { + str = $"x{a.Id + 1}z-{a.CreateTime.ToString("yyyyMM")}{a.Title}", + str2 = string.Format("{0}x{0}z-{1}{2}", a.Id + 1, a.CreateTime.ToString("yyyyMM"), a.Title) + }); + Assert.NotNull(item2); + Assert.Equal($"x{item.Id + 1}z-{item.CreateTime.ToString("yyyyMM")}{item.Title}", item2.str); + Assert.Equal(string.Format("{0}x{0}z-{1}{2}", item.Id + 1, item.CreateTime.ToString("yyyyMM"), item.Title), item2.str2); + } + + [Fact] + public void Format4() + { + //3 {} ʱArguments Ƿֿ + //4 {} ʱArguments[1] ֻܽȻ NewArray [] + var item = g.kingbaseES.GetRepository().Insert(new Topic { Clicks = 101, Title = "й101", CreateTime = DateTime.Parse("2020-7-5") }); + var sql = select.WhereDynamic(item).ToSql(a => new + { + str = $"x{a.Id + 1}z-{a.CreateTime.ToString("yyyyMM")}{a.Title}{a.Title}", + str2 = string.Format("{0}x{0}z-{1}{2}{3}", a.Id + 1, a.CreateTime.ToString("yyyyMM"), a.Title, a.Title) + }); + Assert.Equal($@"SELECT 'x'||coalesce(((a.""ID"" + 1))::text, '')||'z-'||coalesce(to_char((a.""CREATETIME"")::timestamp,'YYYYMM'), '')||''||coalesce(a.""TITLE"", '')||''||coalesce(a.""TITLE"", '')||'' as1, ''||coalesce(((a.""ID"" + 1))::text, '')||'x'||coalesce(((a.""ID"" + 1))::text, '')||'z-'||coalesce(to_char((a.""CREATETIME"")::timestamp,'YYYYMM'), '')||''||coalesce(a.""TITLE"", '')||''||coalesce(a.""TITLE"", '')||'' as2 +FROM ""TB_TOPIC"" a +WHERE (a.""ID"" = {item.Id})", sql); + + var item2 = select.WhereDynamic(item).First(a => new + { + str = $"x{a.Id + 1}z-{a.CreateTime.ToString("yyyyMM")}{a.Title}{a.Title}", + str2 = string.Format("{0}x{0}z-{1}{2}{3}", a.Id + 1, a.CreateTime.ToString("yyyyMM"), a.Title, a.Title) + }); + Assert.NotNull(item2); + Assert.Equal($"x{item.Id + 1}z-{item.CreateTime.ToString("yyyyMM")}{item.Title}{item.Title}", item2.str); + Assert.Equal(string.Format("{0}x{0}z-{1}{2}{3}", item.Id + 1, item.CreateTime.ToString("yyyyMM"), item.Title, item.Title), item2.str2); + } + + [Fact] + public void Empty() + { + var data = new List(); + data.Add(select.Where(a => (a.Title ?? "") == string.Empty).ToSql()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (ifnull(a.`Title`, '') = '') + } + + [Fact] + public void StartsWith() + { + var list = new List(); + list.Add(select.Where(a => a.Title.StartsWith("aaa")).ToList()); + list.Add(select.Where(a => a.Title.StartsWith(a.Title)).ToList()); + list.Add(select.Where(a => a.Title.StartsWith(a.Title + 1)).ToList()); + list.Add(select.Where(a => a.Title.StartsWith(a.Type.Name)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE '%aaa') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', a.`Title`)) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', concat(a.`Title`, 1))) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE((a.`Title`) LIKE concat('%', a__Type.`Name`)) + list.Add(select.Where(a => (a.Title + "aaa").StartsWith("aaa")).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").StartsWith(a.Title)).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").StartsWith(a.Title + 1)).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").StartsWith(a.Type.Name)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE '%aaa') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', a.`Title`)) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', concat(a.`Title`, 1))) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', a__Type.`Name`)) + } + [Fact] + public void EndsWith() + { + var list = new List(); + list.Add(select.Where(a => a.Title.EndsWith("aaa")).ToList()); + list.Add(select.Where(a => a.Title.EndsWith(a.Title)).ToList()); + list.Add(select.Where(a => a.Title.EndsWith(a.Title + 1)).ToList()); + list.Add(select.Where(a => a.Title.EndsWith(a.Type.Name)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE 'aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat(a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat(concat(a.`Title`, 1), '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE((a.`Title`) LIKE concat(a__Type.`Name`, '%')) + list.Add(select.Where(a => (a.Title + "aaa").EndsWith("aaa")).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").EndsWith(a.Title)).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").EndsWith(a.Title + 1)).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").EndsWith(a.Type.Name)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE 'aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat(a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat(concat(a.`Title`, 1), '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat(a__Type.`Name`, '%')) + } + [Fact] + public void Contains() + { + var list = new List(); + list.Add(select.Where(a => a.Title.Contains("aaa")).ToList()); + list.Add(select.Where(a => a.Title.Contains(a.Title)).ToList()); + list.Add(select.Where(a => a.Title.Contains(a.Title + 1)).ToList()); + list.Add(select.Where(a => a.Title.Contains(a.Type.Name)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE '%aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', a.`Title` +1, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE((a.`Title`) LIKE concat('%', a__Type.`Name`, '%')) + list.Add(select.Where(a => (a.Title + "aaa").Contains("aaa")).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").Contains(a.Title)).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").Contains(a.Title + 1)).ToList()); + list.Add(select.Where(a => (a.Title + "aaa").Contains(a.Type.Name)).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE '%aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', concat(a.`Title`, 1), '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', a__Type.`Name`, '%')) + } + [Fact] + public void ToLower() + { + var data = new List(); + data.Add(select.Where(a => a.Title.ToLower() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.ToLower() == a.Title).ToList()); + data.Add(select.Where(a => a.Title.ToLower() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.ToLower() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(a.`Title`) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE(lower(a.`Title`) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = a__Type.`Name`) + } + [Fact] + public void ToUpper() + { + var data = new List(); + data.Add(select.Where(a => a.Title.ToUpper() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.ToUpper() == a.Title).ToList()); + data.Add(select.Where(a => a.Title.ToUpper() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.ToUpper() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(a.`Title`) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (upper(a.`Title`) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = a__Type.`Name`) + } + [Fact] + public void Substring() + { + var data = new List(); + data.Add(select.Where(a => a.Title.Substring(0) == "aaa").ToList()); + data.Add(select.Where(a => a.Title.Substring(0) == a.Title).ToList()); + data.Add(select.Where(a => a.Title.Substring(0) == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.Substring(0) == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(a.`Title`, 1) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(a.`Title`, 1) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(a.`Title`, 1) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (substr(a.`Title`, 1) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(a.Title.Length) == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(0, a.Title.Length) == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(0, 3) == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(1, 2) == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), char_length(a.`Title`) + 1) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), 1, char_length(a.`Title`)) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), 1, 3) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), 2, 2) = a__Type.`Name`) + } + [Fact] + public void Length() + { + var data = new List(); + data.Add(select.Where(a => a.Title.Length == 0).ToList()); + data.Add(select.Where(a => a.Title.Length == 1).ToList()); + data.Add(select.Where(a => a.Title.Length == a.Title.Length + 1).ToList()); + data.Add(select.Where(a => a.Title.Length == a.Type.Name.Length).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(a.`Title`) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(a.`Title`) = 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(a.`Title`) = char_length(a.`Title`) + 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (char_length(a.`Title`) = char_length(a__Type.`Name`)); + data.Add(select.Where(a => (a.Title + "aaa").Length == 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").Length == 1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").Length == a.Title.Length + 1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").Length == a.Type.Name.Length).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(concat(a.`Title`, 'aaa')) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(concat(a.`Title`, 'aaa')) = 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(concat(a.`Title`, 'aaa')) = char_length(a.`Title`) + 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (char_length(concat(a.`Title`, 'aaa')) = char_length(a__Type.`Name`)) + } + [Fact] + public void IndexOf() + { + var data = new List(); + data.Add(select.Where(a => a.Title.IndexOf("aaa") == -1).ToList()); + data.Add(select.Where(a => a.Title.IndexOf("aaa", 2) == -1).ToList()); + data.Add(select.Where(a => a.Title.IndexOf("aaa", 2) == (a.Title.Length + 1)).ToList()); + data.Add(select.Where(a => a.Title.IndexOf("aaa", 2) == a.Type.Name.Length + 1).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(a.`Title`, 'aaa') - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(a.`Title`, 'aaa', 3) - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(a.`Title`, 'aaa', 3) - 1) = char_length(a.`Title`) + 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE ((locate(a.`Title`, 'aaa', 3) - 1) = char_length(a__Type.`Name`) + 1); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa") == -1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa", 2) == -1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa", 2) == (a.Title.Length + 1)).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa", 2) == a.Type.Name.Length + 1).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa') - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa', 3) - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa', 3) - 1) = char_length(a.`Title`) + 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa', 3) - 1) = char_length(a__Type.`Name`) + 1) + } + [Fact] + public void PadLeft() + { + var data = new List(); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == "aaa").ToList()); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(a.`Title`, 10, 'a') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(a.`Title`, 10, 'a') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(a.`Title`, 10, 'a') = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (lpad(a.`Title`, 10, 'a') = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a__Type.`Name`) + } + [Fact] + public void PadRight() + { + var data = new List(); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == "aaa").ToList()); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(a.`Title`, 10, 'a') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(a.`Title`, 10, 'a') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(a.`Title`, 10, 'a') = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (rpad(a.`Title`, 10, 'a') = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a__Type.`Name`) + } + [Fact] + public void Trim() + { + var data = new List(); + data.Add(select.Where(a => a.Title.Trim() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.Trim('a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.Trim('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.Trim('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('a' from a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('b' from trim('a' from a.`Title`)) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (trim('c' from trim('b' from trim('a' from a.`Title`))) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.Trim() + "aaa").Trim() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.Trim('a') + "aaa").Trim('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.Trim('a', 'b') + "aaa").Trim('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.Trim('a', 'b', 'c') + "aaa").Trim('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(concat(trim(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('a' from concat(trim('a' from a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('b' from trim('a' from concat(trim('b' from trim('a' from a.`Title`)), 'aaa'))) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (trim('c' from trim('b' from trim('a' from concat(trim('c' from trim('b' from trim('a' from a.`Title`))), 'aaa')))) = a__Type.`Name`) + } + [Fact] + public void TrimStart() + { + var data = new List(); + data.Add(select.Where(a => a.Title.TrimStart() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.TrimStart('a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.TrimStart('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.TrimStart('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (ltrim(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from trim(leading 'a' from a.`Title`)) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (trim(trailing 'c' from trim(leading 'c' from trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))))) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.TrimStart() + "aaa").TrimStart() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.TrimStart('a') + "aaa").TrimStart('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.TrimStart('a', 'b') + "aaa").TrimStart('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.TrimStart('a', 'b', 'c') + "aaa").TrimStart('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (ltrim(concat(ltrim(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from trim(leading 'a' from concat(trim(trailing 'a' from trim(leading 'a' from a.`Title`)), 'aaa'))) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from concat(trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))), 'aaa'))))) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (trim(trailing 'c' from trim(leading 'c' from trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from concat(trim(trailing 'c' from trim(leading 'c' from trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))))), 'aaa'))))))) = a__Type.`Name`) + } + [Fact] + public void TrimEnd() + { + var data = new List(); + data.Add(select.Where(a => a.Title.TrimEnd() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.TrimEnd('a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.TrimEnd('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.TrimEnd('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rtrim(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(trailing 'a' from a.`Title`)) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (trim(trailing 'c' from trim(trailing 'b' from trim(trailing 'a' from a.`Title`))) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.TrimEnd() + "aaa").TrimEnd() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.TrimEnd('a') + "aaa").TrimEnd('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.TrimEnd('a', 'b') + "aaa").TrimEnd('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.TrimEnd('a', 'b', 'c') + "aaa").TrimEnd('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rtrim(concat(rtrim(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from concat(trim(trailing 'a' from a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(trailing 'a' from concat(trim(trailing 'b' from trim(trailing 'a' from a.`Title`)), 'aaa'))) = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (trim(trailing 'c' from trim(trailing 'b' from trim(trailing 'a' from concat(trim(trailing 'c' from trim(trailing 'b' from trim(trailing 'a' from a.`Title`))), 'aaa')))) = a__Type.`Name`) + } + [Fact] + public void Replace() + { + var data = new List(); + data.Add(select.Where(a => a.Title.Replace("a", "b") == "aaa").ToList()); + data.Add(select.Where(a => a.Title.Replace("a", "b").Replace("b", "c") == a.Title).ToList()); + data.Add(select.Where(a => a.Title.Replace("a", "b").Replace("b", "c").Replace("c", "a") == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.Replace("a", "b").Replace("b", "c").Replace(a.Type.Name, "a") == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (replace(a.`Title`, 'a', 'b') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (replace(replace(a.`Title`, 'a', 'b'), 'b', 'c') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), 'c', 'a') = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), a__Type.`Name`, 'a') = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.Replace("a", "b") + "aaa").TrimEnd() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.Replace("a", "b").Replace("b", "c") + "aaa").TrimEnd('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.Replace("a", "b").Replace("b", "c").Replace("c", "a") + "aaa").TrimEnd('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.Replace("a", "b").Replace("b", "c").Replace(a.Type.Name, "a") + "aaa").TrimEnd('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (concat(replace(a.`Title`, 'a', 'b'), 'aaa') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (concat(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), 'aaa') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (concat(replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), 'c', 'a'), 'aaa') = concat(a.`Title`, 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (concat(replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), a__Type.`Name`, 'a'), 'aaa') = a__Type.`Name`) + } + [Fact] + public void CompareTo() + { + var data = new List(); + data.Add(select.Where(a => a.Title.CompareTo(a.Title) == 0).ToList()); + data.Add(select.Where(a => a.Title.CompareTo(a.Title) > 0).ToList()); + data.Add(select.Where(a => a.Title.CompareTo(a.Title + 1) == 0).ToList()); + data.Add(select.Where(a => a.Title.CompareTo(a.Title + a.Type.Name) == 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(a.`Title`, a.`Title`) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(a.`Title`, a.`Title`) > 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(a.`Title`, concat(a.`Title`, 1)) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (strcmp(a.`Title`, concat(a.`Title`, a__Type.`Name`)) = 0); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo("aaa") == 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Title) > 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Title + 1) == 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Type.Name) == 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(concat(a.`Title`, 'aaa'), 'aaa') = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(concat(a.`Title`, 'aaa'), a.`Title`) > 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(concat(a.`Title`, 'aaa'), concat(a.`Title`, 1)) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 + //FROM `tb_topic` a, `TestTypeInfo` a__Type + //WHERE (strcmp(concat(a.`Title`, 'aaa'), a__Type.`Name`) = 0) + } + + [Fact] + public void string_IsNullOrEmpty() + { + var data = new List(); + data.Add(select.Where(a => string.IsNullOrEmpty(a.Title)).ToList()); + data.Add(select.Where(a => !string.IsNullOrEmpty(a.Title)).ToList()); + } + + [Fact] + public void string_IsNullOrWhiteSpace() + { + var data = new List(); + data.Add(select.Where(a => string.IsNullOrWhiteSpace(a.Title)).ToList()); + data.Add(select.Where(a => !string.IsNullOrWhiteSpace(a.Title)).ToList()); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/TimeSpanTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/TimeSpanTest.cs new file mode 100644 index 00000000..155797cb --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/KingbaseESExpression/TimeSpanTest.cs @@ -0,0 +1,293 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.KingbaseESExpression +{ + public class TimeSpanTest + { + + ISelect select => g.kingbaseES.Select(); + + [Table(Name = "tb_topic")] + class Topic + { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TypeGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo + { + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo + { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + [Fact] + public void Zero() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay > TimeSpan.Zero).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) > 0) + } + [Fact] + public void MinValue() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay > TimeSpan.MinValue).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) > -922337203685477580) + } + [Fact] + public void MaxValue() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay < TimeSpan.MaxValue).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) < 922337203685477580) + } + [Fact] + public void Days() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Days == 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) div 86400000000) = 0) + } + [Fact] + public void Hours() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Hours > 0).ToSql()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) div 3600000000) mod 24 > 0) + } + [Fact] + public void Milliseconds() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Milliseconds > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) div 1000 mod 1000) > 0) + } + [Fact] + public void Minutes() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Minutes > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) div 60000000 mod 60) > 0) + } + [Fact] + public void Seconds() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Seconds > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) div 1000000 mod 60) > 0) + } + [Fact] + public void Ticks() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Ticks > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) * 10) > 0) + } + [Fact] + public void TotalDays() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.TotalDays > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) / 86400000000) > 0) + } + [Fact] + public void TotalHours() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.TotalHours > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) / 3600000000) > 0) + } + [Fact] + public void TotalMilliseconds() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.TotalMilliseconds > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) / 1000) > 0) + } + [Fact] + public void TotalMinutes() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.TotalMinutes > 0).ToSql()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) / 60000000) > 0) + } + [Fact] + public void TotalSeconds() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.TotalSeconds > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) / 1000000) > 0) + } + [Fact] + public void Add() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Add(TimeSpan.FromDays(1)) > TimeSpan.Zero).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) + (1 * 86400000000)) > 0) + } + [Fact] + public void Subtract() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Subtract(TimeSpan.FromDays(1)) > TimeSpan.Zero).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) - (1 * 86400000000)) > 0) + } + [Fact] + public void CompareTo() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.CompareTo(TimeSpan.FromDays(1)) > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) - ((1 * 86400000000))) > 0) + } + [Fact] + public void this_Equals() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.Equals(TimeSpan.FromDays(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 86400000000))) + } + [Fact] + public void this_ToString() + { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.TimeOfDay.ToString() == "ssss").ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (date_format(date_add(cast('0001/1/1 0:00:00' as datetime), interval (timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) microsecond), '%Y-%m-%d %H:%i:%s.%f') = 'ssss') + } + + [Fact] + public void TimeSpan_Compare() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Compare(a.CreateTime.TimeOfDay, TimeSpan.FromDays(1)) > 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) - ((1 * 86400000000))) > 0) + } + [Fact] + public void TimeSpan_Equals() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromDays(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 86400000000))) + } + [Fact] + public void TimeSpan_FromDays() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromDays(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 86400000000))) + } + [Fact] + public void TimeSpan_FromHours() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromHours(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 3600000000))) + } + [Fact] + public void TimeSpan_FromMilliseconds() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromMilliseconds(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 1000))) + } + [Fact] + public void TimeSpan_FromMinutes() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromMinutes(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 60000000))) + } + [Fact] + public void TimeSpan_FromSeconds() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromSeconds(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 * 1000000))) + } + [Fact] + public void TimeSpan_FromTicks() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Equals(a.CreateTime.TimeOfDay, TimeSpan.FromTicks(1))).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000) = (1 / 10))) + } + [Fact] + public void TimeSpan_Parse() + { + var data = new List(); + data.Add(select.Where(a => TimeSpan.Parse(a.CreateTime.TimeOfDay.ToString()) > TimeSpan.Zero).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TypeGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (cast(date_format(date_add(cast('0001/1/1 0:00:00' as datetime), interval (timestampdiff(microsecond, date_format(a.`CreateTime`, '1970-1-1 %H:%i:%s.%f'), a.`CreateTime`) + 62135596800000000)) microsecond), '%Y-%m-%d %H:%i:%s.%f') as signed) > 0) + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolNullableTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolNullableTest.cs new file mode 100644 index 00000000..6035da7b --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolNullableTest.cs @@ -0,0 +1,1571 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.KingbaseESMapType +{ + public class BoolNullableTest + { + class BoolNullableMap + { + public Guid id { get; set; } + [Column(MapType = typeof(bool))] + public bool? tobool { get; set; } = true; + + [Column(MapType = typeof(sbyte))] + public bool? tosbyte { get; set; } = true; + [Column(MapType = typeof(sbyte?))] + public bool? tosbytenullable { get; set; } = true; + + [Column(MapType = typeof(short))] + public bool? toshort { get; set; } = true; + + [Column(MapType = typeof(short?))] + public bool? toshortnullable { get; set; } = true; + + [Column(MapType = typeof(int))] + public bool? toint { get; set; } = true; + + [Column(MapType = typeof(int?))] + public bool? tointnullable { get; set; } = true; + + [Column(MapType = typeof(long))] + public bool? tolong { get; set; } = true; + [Column(MapType = typeof(long?))] + public bool? tolongnullable { get; set; } = true; + + [Column(MapType = typeof(byte))] + public bool? tobyte { get; set; } = true; + [Column(MapType = typeof(byte?))] + public bool? tobytenullable { get; set; } = true; + + [Column(MapType = typeof(ushort))] + public bool? toushort { get; set; } = true; + + [Column(MapType = typeof(ushort?))] + public bool? toushortnullable { get; set; } = true; + + [Column(MapType = typeof(uint))] + public bool? touint { get; set; } = true; + + [Column(MapType = typeof(uint?))] + public bool? touintnullable { get; set; } = true; + + [Column(MapType = typeof(ulong))] + public bool? toulong { get; set; } = true; + [Column(MapType = typeof(ulong?))] + public bool? toulongnullable { get; set; } = true; + + [Column(MapType = typeof(string))] + public bool? tostring { get; set; } = true; + } + [Fact] + public void Bool() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tobool == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobool, find.tobool); + Assert.Equal(true, find.tobool); + + item = new BoolNullableMap { tobool = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobool, find.tobool); + Assert.Equal(false, find.tobool); + + item = new BoolNullableMap { tobool = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobool == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tobool, find.tobool); + Assert.Equal(false, find.tobool); + + //update all + item.tobool = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobool, find.tobool); + Assert.Equal(true, find.tobool); + + item.tobool = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobool, find.tobool); + Assert.Equal(false, find.tobool); + + item.tobool = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobool == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tobool, find.tobool); + Assert.Equal(false, find.tobool); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobool, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tobool); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobool, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tobool); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobool, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobool == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobool == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tobool); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobool == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobool == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tobool == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void SByte() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tosbyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.Equal(true, find.tosbyte); + + item = new BoolNullableMap { tosbyte = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.Equal(false, find.tosbyte); + + item = new BoolNullableMap { tosbyte = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tosbyte == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tosbyte, find.tosbyte); + Assert.Equal(false, find.tosbyte); + + //update all + item.tosbyte = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.Equal(true, find.tosbyte); + + item.tosbyte = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.Equal(false, find.tosbyte); + + item.tosbyte = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tosbyte == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tosbyte, find.tosbyte); + Assert.Equal(false, find.tosbyte); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbyte, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tosbyte); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbyte, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tosbyte); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbyte, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tosbyte == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tosbyte); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tosbyte == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tosbyte == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tosbyte == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void SByteNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.Equal(true, find.tosbytenullable); + + item = new BoolNullableMap { tosbytenullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.Equal(false, find.tosbytenullable); + + item = new BoolNullableMap { tosbytenullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.Null(find.tosbytenullable); + + //update all + item.tosbytenullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.Equal(true, find.tosbytenullable); + + item.tosbytenullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.Equal(false, find.tosbytenullable); + + item.tosbytenullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.Null(find.tosbytenullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbytenullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tosbytenullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbytenullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tosbytenullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbytenullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.tosbytenullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tosbytenullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tosbytenullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tosbytenullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void Short() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toshort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.Equal(true, find.toshort); + + item = new BoolNullableMap { toshort = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.Equal(false, find.toshort); + + item = new BoolNullableMap { toshort = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toshort == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toshort, find.toshort); + Assert.Equal(false, find.toshort); + + //update all + item.toshort = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.Equal(true, find.toshort); + + item.toshort = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.Equal(false, find.toshort); + + item.toshort = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toshort == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toshort, find.toshort); + Assert.Equal(false, find.toshort); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshort, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toshort); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshort, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toshort); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshort, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toshort == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toshort); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toshort == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toshort == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toshort == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ShortNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.Equal(true, find.toshortnullable); + + item = new BoolNullableMap { toshortnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.Equal(false, find.toshortnullable); + + item = new BoolNullableMap { toshortnullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.Null(find.toshortnullable); + + //update all + item.toshortnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.Equal(true, find.toshortnullable); + + item.toshortnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.Equal(false, find.toshortnullable); + + item.toshortnullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.Null(find.toshortnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshortnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toshortnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshortnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toshortnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshortnullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.toshortnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toshortnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toshortnullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toshortnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void Int() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.Equal(true, find.toint); + + item = new BoolNullableMap { toint = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.Equal(false, find.toint); + + item = new BoolNullableMap { toint = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toint == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toint, find.toint); + Assert.Equal(false, find.toint); + + //update all + item.toint = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.Equal(true, find.toint); + + item.toint = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.Equal(false, find.toint); + + item.toint = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toint == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toint, find.toint); + Assert.Equal(false, find.toint); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toint, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toint); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toint, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toint); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toint, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toint == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toint); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toint == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toint == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toint == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void IntNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tointnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.Equal(true, find.tointnullable); + + item = new BoolNullableMap { tointnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.Equal(false, find.tointnullable); + + item = new BoolNullableMap { tointnullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.Null(find.tointnullable); + + //update all + item.tointnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.Equal(true, find.tointnullable); + + item.tointnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.Equal(false, find.tointnullable); + + item.tointnullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.Null(find.tointnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tointnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tointnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tointnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tointnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tointnullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.tointnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tointnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tointnullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tointnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void Long() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tolong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.Equal(true, find.tolong); + + item = new BoolNullableMap { tolong = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.Equal(false, find.tolong); + + item = new BoolNullableMap { tolong = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tolong == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tolong, find.tolong); + Assert.Equal(false, find.tolong); + + //update all + item.tolong = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.Equal(true, find.tolong); + + item.tolong = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.Equal(false, find.tolong); + + item.tolong = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tolong == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tolong, find.tolong); + Assert.Equal(false, find.tolong); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolong, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tolong); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolong, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tolong); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolong, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tolong == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tolong); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tolong == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tolong == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tolong == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void LongNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.Equal(true, find.tolongnullable); + + item = new BoolNullableMap { tolongnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.Equal(false, find.tolongnullable); + + item = new BoolNullableMap { tolongnullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.Null(find.tolongnullable); + + //update all + item.tolongnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.Equal(true, find.tolongnullable); + + item.tolongnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.Equal(false, find.tolongnullable); + + item.tolongnullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.Null(find.tolongnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolongnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tolongnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolongnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tolongnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolongnullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.tolongnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tolongnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tolongnullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tolongnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void Byte() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tobyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.Equal(true, find.tobyte); + + item = new BoolNullableMap { tobyte = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.Equal(false, find.tobyte); + + item = new BoolNullableMap { tobyte = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobyte == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tobyte, find.tobyte); + Assert.Equal(false, find.tobyte); + + //update all + item.tobyte = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.Equal(true, find.tobyte); + + item.tobyte = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.Equal(false, find.tobyte); + + item.tobyte = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobyte == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.tobyte, find.tobyte); + Assert.Equal(false, find.tobyte); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobyte, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tobyte); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobyte, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tobyte); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobyte, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobyte == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tobyte); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobyte == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobyte == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tobyte == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ByteNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.Equal(true, find.tobytenullable); + + item = new BoolNullableMap { tobytenullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.Equal(false, find.tobytenullable); + + item = new BoolNullableMap { tobytenullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.Null(find.tobytenullable); + + //update all + item.tobytenullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.Equal(true, find.tobytenullable); + + item.tobytenullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.Equal(false, find.tobytenullable); + + item.tobytenullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.Null(find.tobytenullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobytenullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tobytenullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobytenullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tobytenullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobytenullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.tobytenullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobytenullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tobytenullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobytenullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UShort() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toushort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.Equal(true, find.toushort); + + item = new BoolNullableMap { toushort = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.Equal(false, find.toushort); + + item = new BoolNullableMap { toushort = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toushort == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toushort, find.toushort); + Assert.Equal(false, find.toushort); + + //update all + item.toushort = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.Equal(true, find.toushort); + + item.toushort = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.Equal(false, find.toushort); + + item.toushort = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toushort == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toushort, find.toushort); + Assert.Equal(false, find.toushort); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushort, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toushort); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushort, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toushort); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushort, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toushort == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toushort); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toushort == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toushort == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toushort == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UShortNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.Equal(true, find.toushortnullable); + + item = new BoolNullableMap { toushortnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.Equal(false, find.toushortnullable); + + item = new BoolNullableMap { toushortnullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.Null(find.toushortnullable); + + //update all + item.toushortnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.Equal(true, find.toushortnullable); + + item.toushortnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.Equal(false, find.toushortnullable); + + item.toushortnullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.Null(find.toushortnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushortnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toushortnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushortnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toushortnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushortnullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.toushortnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toushortnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toushortnullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toushortnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UInt() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.touint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.Equal(true, find.touint); + + item = new BoolNullableMap { touint = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.Equal(false, find.touint); + + item = new BoolNullableMap { touint = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.touint == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.touint, find.touint); + Assert.Equal(false, find.touint); + + //update all + item.touint = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.Equal(true, find.touint); + + item.touint = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.Equal(false, find.touint); + + item.touint = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.touint == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.touint, find.touint); + Assert.Equal(false, find.touint); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touint, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.touint); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touint, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.touint); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touint, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.touint == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.touint); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.touint == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.touint == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.touint == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UIntNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.touintnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.Equal(true, find.touintnullable); + + item = new BoolNullableMap { touintnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.Equal(false, find.touintnullable); + + item = new BoolNullableMap { touintnullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.Null(find.touintnullable); + + //update all + item.touintnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.Equal(true, find.touintnullable); + + item.touintnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.Equal(false, find.touintnullable); + + item.touintnullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.Null(find.touintnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touintnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.touintnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touintnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.touintnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touintnullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.touintnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.touintnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.touintnullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.touintnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ULong() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toulong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.Equal(true, find.toulong); + + item = new BoolNullableMap { toulong = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.Equal(false, find.toulong); + + item = new BoolNullableMap { toulong = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toulong == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toulong, find.toulong); + Assert.Equal(false, find.toulong); + + //update all + item.toulong = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.Equal(true, find.toulong); + + item.toulong = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.Equal(false, find.toulong); + + item.toulong = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toulong == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.NotEqual(item.toulong, find.toulong); + Assert.Equal(false, find.toulong); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulong, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toulong); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulong, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toulong); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulong, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toulong == null).First()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toulong); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toulong == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toulong == null).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toulong == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ULongNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.Equal(true, find.toulongnullable); + + item = new BoolNullableMap { toulongnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.Equal(false, find.toulongnullable); + + item = new BoolNullableMap { toulongnullable = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.Null(find.toulongnullable); + + //update all + item.toulongnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.Equal(true, find.toulongnullable); + + item.toulongnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.Equal(false, find.toulongnullable); + + item.toulongnullable = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.Null(find.toulongnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulongnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.toulongnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulongnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.toulongnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulongnullable, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.toulongnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toulongnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toulongnullable == null).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toulongnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void TimeSpan() + { + } + [Fact] + public void TimeSpanNullable() + { + } + [Fact] + public void DateTime() + { + } + [Fact] + public void DateTimeNullable() + { + } + + [Fact] + public void ByteArray() + { + } + [Fact] + public void String() + { + //insert + var orm = g.kingbaseES; + var item = new BoolNullableMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tostring == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.Equal(true, find.tostring); + + item = new BoolNullableMap { tostring = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.Equal(false, find.tostring); + + item = new BoolNullableMap { tostring = null }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tostring == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.Null(find.tostring); + + //update all + item.tostring = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.Equal(true, find.tostring); + + item.tostring = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.Equal(false, find.tostring); + + item.tostring = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tostring == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.Null(find.tostring); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tostring, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(true, find.tostring); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tostring, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(false, find.tostring); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tostring, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.tostring == false).First()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.tostring); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tostring == true).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tostring == false).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tostring == null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void Guid() + { + } + [Fact] + public void GuidNullable() + { + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolTest.cs new file mode 100644 index 00000000..51e28099 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/BoolTest.cs @@ -0,0 +1,1105 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.KingbaseESMapType +{ + public class BoolTest + { + + class BoolMap + { + public Guid id { get; set; } + [Column(MapType = typeof(bool?))] + public bool toboolnullable { get; set; } = true; + + [Column(MapType = typeof(sbyte))] + public bool tosbyte { get; set; } = true; + [Column(MapType = typeof(sbyte?))] + public bool tosbytenullable { get; set; } = true; + + [Column(MapType = typeof(short))] + public bool toshort { get; set; } = true; + + [Column(MapType = typeof(short?))] + public bool toshortnullable { get; set; } = true; + + [Column(MapType = typeof(int))] + public bool toint { get; set; } = true; + + [Column(MapType = typeof(int?))] + public bool tointnullable { get; set; } = true; + + [Column(MapType = typeof(long))] + public bool tolong { get; set; } = true; + [Column(MapType = typeof(long?))] + public bool tolongnullable { get; set; } = true; + + [Column(MapType = typeof(byte))] + public bool tobyte { get; set; } = true; + [Column(MapType = typeof(byte?))] + public bool tobytenullable { get; set; } = true; + + [Column(MapType = typeof(ushort))] + public bool toushort { get; set; } = true; + + [Column(MapType = typeof(ushort?))] + public bool toushortnullable { get; set; } = true; + + [Column(MapType = typeof(uint))] + public bool touint { get; set; } = true; + + [Column(MapType = typeof(uint?))] + public bool touintnullable { get; set; } = true; + + [Column(MapType = typeof(ulong))] + public bool toulong { get; set; } = true; + [Column(MapType = typeof(ulong?))] + public bool toulongnullable { get; set; } = true; + + [Column(MapType = typeof(string))] + public bool tostring { get; set; } = true; + } + + [Fact] + public void BoolNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toboolnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toboolnullable, find.toboolnullable); + Assert.True(find.toboolnullable); + + item = new BoolMap { toboolnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toboolnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toboolnullable, find.toboolnullable); + Assert.False(find.toboolnullable); + + //update all + item.toboolnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toboolnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toboolnullable, find.toboolnullable); + Assert.True(find.toboolnullable); + + item.toboolnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toboolnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toboolnullable, find.toboolnullable); + Assert.False(find.toboolnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toboolnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toboolnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toboolnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toboolnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toboolnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toboolnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toboolnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toboolnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void SByte() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tosbyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.True(find.tosbyte); + + item = new BoolMap { tosbyte = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.False(find.tosbyte); + + //update all + item.tosbyte = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.True(find.tosbyte); + + item.tosbyte = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbyte, find.tosbyte); + Assert.False(find.tosbyte); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbyte, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tosbyte); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbyte, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tosbyte); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tosbyte == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tosbyte == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void SByteNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.True(find.tosbytenullable); + + item = new BoolMap { tosbytenullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.False(find.tosbytenullable); + + //update all + item.tosbytenullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.True(find.tosbytenullable); + + item.tosbytenullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tosbytenullable, find.tosbytenullable); + Assert.False(find.tosbytenullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbytenullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tosbytenullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tosbytenullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tosbytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tosbytenullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tosbytenullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tosbytenullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void Short() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toshort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.True(find.toshort); + + item = new BoolMap { toshort = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.False(find.toshort); + + //update all + item.toshort = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.True(find.toshort); + + item.toshort = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshort, find.toshort); + Assert.False(find.toshort); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshort, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toshort); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshort, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toshort); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toshort == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toshort == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ShortNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.True(find.toshortnullable); + + item = new BoolMap { toshortnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.False(find.toshortnullable); + + //update all + item.toshortnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.True(find.toshortnullable); + + item.toshortnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toshortnullable, find.toshortnullable); + Assert.False(find.toshortnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshortnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toshortnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toshortnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toshortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toshortnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toshortnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toshortnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void Int() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.True(find.toint); + + item = new BoolMap { toint = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.False(find.toint); + + //update all + item.toint = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.True(find.toint); + + item.toint = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toint, find.toint); + Assert.False(find.toint); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toint, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toint); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toint, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toint); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toint == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toint == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void IntNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tointnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.True(find.tointnullable); + + item = new BoolMap { tointnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.False(find.tointnullable); + + //update all + item.tointnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.True(find.tointnullable); + + item.tointnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tointnullable, find.tointnullable); + Assert.False(find.tointnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tointnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tointnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tointnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tointnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tointnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tointnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tointnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void Long() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tolong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.True(find.tolong); + + item = new BoolMap { tolong = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.False(find.tolong); + + //update all + item.tolong = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.True(find.tolong); + + item.tolong = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolong, find.tolong); + Assert.False(find.tolong); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolong, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tolong); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolong, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tolong); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tolong == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tolong == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void LongNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.True(find.tolongnullable); + + item = new BoolMap { tolongnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.False(find.tolongnullable); + + //update all + item.tolongnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.True(find.tolongnullable); + + item.tolongnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tolongnullable, find.tolongnullable); + Assert.False(find.tolongnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolongnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tolongnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tolongnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tolongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tolongnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tolongnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tolongnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void Byte() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tobyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.True(find.tobyte); + + item = new BoolMap { tobyte = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.False(find.tobyte); + + //update all + item.tobyte = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.True(find.tobyte); + + item.tobyte = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobyte, find.tobyte); + Assert.False(find.tobyte); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobyte, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tobyte); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobyte, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobyte == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tobyte); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobyte == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tobyte == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ByteNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.True(find.tobytenullable); + + item = new BoolMap { tobytenullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.False(find.tobytenullable); + + //update all + item.tobytenullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.True(find.tobytenullable); + + item.tobytenullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tobytenullable, find.tobytenullable); + Assert.False(find.tobytenullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobytenullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tobytenullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tobytenullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tobytenullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tobytenullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tobytenullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tobytenullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UShort() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toushort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.True(find.toushort); + + item = new BoolMap { toushort = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.False(find.toushort); + + //update all + item.toushort = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.True(find.toushort); + + item.toushort = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushort, find.toushort); + Assert.False(find.toushort); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushort, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toushort); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushort, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushort == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toushort); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toushort == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toushort == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UShortNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.True(find.toushortnullable); + + item = new BoolMap { toushortnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.False(find.toushortnullable); + + //update all + item.toushortnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.True(find.toushortnullable); + + item.toushortnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toushortnullable, find.toushortnullable); + Assert.False(find.toushortnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushortnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toushortnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toushortnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toushortnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toushortnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toushortnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toushortnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UInt() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.touint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.True(find.touint); + + item = new BoolMap { touint = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.False(find.touint); + + //update all + item.touint = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.True(find.touint); + + item.touint = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touint, find.touint); + Assert.False(find.touint); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touint, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.touint); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touint, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touint == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.touint); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.touint == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.touint == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void UIntNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.touintnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.True(find.touintnullable); + + item = new BoolMap { touintnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.False(find.touintnullable); + + //update all + item.touintnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.True(find.touintnullable); + + item.touintnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.touintnullable, find.touintnullable); + Assert.False(find.touintnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touintnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.touintnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.touintnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.touintnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.touintnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.touintnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.touintnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ULong() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toulong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.True(find.toulong); + + item = new BoolMap { toulong = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.False(find.toulong); + + //update all + item.toulong = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.True(find.toulong); + + item.toulong = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulong, find.toulong); + Assert.False(find.toulong); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulong, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toulong); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulong, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulong == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toulong); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toulong == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toulong == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void ULongNullable() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.True(find.toulongnullable); + + item = new BoolMap { toulongnullable = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.False(find.toulongnullable); + + //update all + item.toulongnullable = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.True(find.toulongnullable); + + item.toulongnullable = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.toulongnullable, find.toulongnullable); + Assert.False(find.toulongnullable); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulongnullable, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.toulongnullable); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.toulongnullable, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.toulongnullable == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.toulongnullable); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.toulongnullable == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.toulongnullable == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void TimeSpan() + { + } + [Fact] + public void TimeSpanNullable() + { + } + [Fact] + public void DateTime() + { + } + [Fact] + public void DateTimeNullable() + { + } + + [Fact] + public void ByteArray() + { + } + [Fact] + public void String() + { + //insert + var orm = g.kingbaseES; + var item = new BoolMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.tostring == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.True(find.tostring); + + item = new BoolMap { tostring = false }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.False(find.tostring); + + //update all + item.tostring = true; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.True(find.tostring); + + item.tostring = false; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.tostring, find.tostring); + Assert.False(find.tostring); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tostring, true).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == true).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.True(find.tostring); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.tostring, false).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.tostring == false).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.False(find.tostring); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.tostring == true).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.tostring == false).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void Guid() + { + } + [Fact] + public void GuidNullable() + { + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/DateTimeOffSetTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/DateTimeOffSetTest.cs new file mode 100644 index 00000000..cf40ca11 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/DateTimeOffSetTest.cs @@ -0,0 +1,54 @@ +using FreeSql.DataAnnotations; +using System; +using System.Numerics; +using Xunit; + +namespace FreeSql.Tests.KingbaseESMapType +{ + public class DateTimeOffSetTest + { + class Dtos_dt + { + public Guid id { get; set; } + + [Column(MapType = typeof(DateTime))] + public DateTimeOffset dtos_to_dt { get; set; } + [Column(MapType = typeof(DateTime))] + public DateTimeOffset? dtofnil_to_dt { get; set; } + } + [Fact] + public void DateTimeToDateTimeOffSet() + { + //insert + var orm = g.kingbaseES; + var item = new Dtos_dt { dtos_to_dt = DateTimeOffset.Now, dtofnil_to_dt = DateTimeOffset.Now }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.dtos_to_dt.ToString("g"), find.dtos_to_dt.ToString("g")); + Assert.Equal(item.dtofnil_to_dt.Value.ToString("g"), find.dtofnil_to_dt.Value.ToString("g")); + + //update all + item.dtos_to_dt = DateTimeOffset.Now; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.dtos_to_dt.ToString("g"), find.dtos_to_dt.ToString("g")); + Assert.Equal(item.dtofnil_to_dt.Value.ToString("g"), find.dtofnil_to_dt.Value.ToString("g")); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.dtos_to_dt, item.dtos_to_dt = DateTimeOffset.Now).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.dtos_to_dt.ToString("g"), find.dtos_to_dt.ToString("g")); + Assert.Equal(item.dtofnil_to_dt.Value.ToString("g"), find.dtofnil_to_dt.Value.ToString("g")); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/EnumTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/EnumTest.cs new file mode 100644 index 00000000..ebee3c47 --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/EnumTest.cs @@ -0,0 +1,261 @@ +using FreeSql.DataAnnotations; +using System; +using System.Numerics; +using Xunit; + +namespace FreeSql.Tests.KingbaseESMapType +{ + public class EnumTest + { + class EnumTestMap + { + public Guid id { get; set; } + + [Column(MapType = typeof(string))] + public ToStringMapEnum enum_to_string { get; set; } + [Column(MapType = typeof(string))] + public ToStringMapEnum? enumnullable_to_string { get; set; } + + [Column(MapType = typeof(int))] + public ToStringMapEnum enum_to_int { get; set; } + [Column(MapType = typeof(int?))] + public ToStringMapEnum? enumnullable_to_int { get; set; } + } + public enum ToStringMapEnum { й, abc, } + [Fact] + public void EnumToString() + { + //insert + var orm = g.kingbaseES; + var item = new EnumTestMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum.й, find.enum_to_string); + + item = new EnumTestMap { enum_to_string = ToStringMapEnum.abc }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum.abc, find.enum_to_string); + + //update all + item.enum_to_string = ToStringMapEnum.; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum., find.enum_to_string); + + item.enum_to_string = ToStringMapEnum.й; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum.й, find.enum_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enum_to_string, ToStringMapEnum.).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum., find.enum_to_string); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enum_to_string, ToStringMapEnum.abc).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum.abc, find.enum_to_string); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.й).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.abc).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void EnumNullableToString() + { + //insert + var orm = g.kingbaseES; + var item = new EnumTestMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Null(find.enumnullable_to_string); + + item = new EnumTestMap { enumnullable_to_string = ToStringMapEnum.й }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Equal(ToStringMapEnum.й, find.enumnullable_to_string); + + //update all + item.enumnullable_to_string = ToStringMapEnum.; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Equal(ToStringMapEnum., find.enumnullable_to_string); + + item.enumnullable_to_string = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.).First()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Null(find.enumnullable_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enumnullable_to_string, ToStringMapEnum.abc).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum.abc, find.enumnullable_to_string); + + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enumnullable_to_string, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.abc).First()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.enumnullable_to_string); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.й).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_string == null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void EnumToInt() + { + //insert + var orm = g.kingbaseES; + var item = new EnumTestMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_int, find.enum_to_int); + Assert.Equal(ToStringMapEnum.й, find.enum_to_int); + + item = new EnumTestMap { enum_to_int = ToStringMapEnum.abc }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_int, find.enum_to_int); + Assert.Equal(ToStringMapEnum.abc, find.enum_to_int); + + //update all + item.enum_to_int = ToStringMapEnum.; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_int, find.enum_to_int); + Assert.Equal(ToStringMapEnum., find.enum_to_int); + + item.enum_to_int = ToStringMapEnum.й; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_int, find.enum_to_int); + Assert.Equal(ToStringMapEnum.й, find.enum_to_int); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enum_to_int, ToStringMapEnum.).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum., find.enum_to_int); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enum_to_int, ToStringMapEnum.abc).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum.abc, find.enum_to_int); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.й).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.enum_to_int == ToStringMapEnum.abc).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void EnumNullableToInt() + { + //insert + var orm = g.kingbaseES; + var item = new EnumTestMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_int, find.enumnullable_to_int); + Assert.Null(find.enumnullable_to_int); + + item = new EnumTestMap { enumnullable_to_int = ToStringMapEnum.й }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_int, find.enumnullable_to_int); + Assert.Equal(ToStringMapEnum.й, find.enumnullable_to_int); + + //update all + item.enumnullable_to_int = ToStringMapEnum.; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_int, find.enumnullable_to_int); + Assert.Equal(ToStringMapEnum., find.enumnullable_to_int); + + item.enumnullable_to_int = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.).First()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_int, find.enumnullable_to_int); + Assert.Null(find.enumnullable_to_int); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enumnullable_to_int, ToStringMapEnum.abc).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum.abc, find.enumnullable_to_int); + + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enumnullable_to_int, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.abc).First()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_int == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.enumnullable_to_int); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.й).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_int == ToStringMapEnum.).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_int == null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/ToStringTest.cs b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/ToStringTest.cs new file mode 100644 index 00000000..2d00035b --- /dev/null +++ b/FreeSql.Tests/FreeSql.Tests/KingbaseES/MapType/ToStringTest.cs @@ -0,0 +1,570 @@ +using FreeSql.DataAnnotations; +using System; +using System.Numerics; +using Xunit; + +namespace FreeSql.Tests.KingbaseESMapType +{ + public class ToStringTest + { + class ToStringMap + { + public Guid id { get; set; } + + [Column(MapType = typeof(string))] + public TimeSpan timespan_to_string { get; set; } + [Column(MapType = typeof(string))] + public TimeSpan? timespannullable_to_string { get; set; } + + [Column(MapType = typeof(string))] + public DateTime datetime_to_string { get; set; } + [Column(MapType = typeof(string))] + public DateTime? datetimenullable_to_string { get; set; } + + [Column(MapType = typeof(string))] + public Guid guid_to_string { get; set; } + [Column(MapType = typeof(string))] + public Guid? guidnullable_to_string { get; set; } + + [Column(MapType = typeof(string))] + public ToStringMapEnum enum_to_string { get; set; } + [Column(MapType = typeof(string))] + public ToStringMapEnum? enumnullable_to_string { get; set; } + + [Column(MapType = typeof(string))] + public BigInteger biginteger_to_string { get; set; } + [Column(MapType = typeof(string))] + public BigInteger? bigintegernullable_to_string { get; set; } + } + public enum ToStringMapEnum { й, abc, } + [Fact] + public void Enum1() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum.й, find.enum_to_string); + + item = new ToStringMap { enum_to_string = ToStringMapEnum.abc }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum.abc, find.enum_to_string); + + //update all + item.enum_to_string = ToStringMapEnum.; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum., find.enum_to_string); + + item.enum_to_string = ToStringMapEnum.й; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enum_to_string, find.enum_to_string); + Assert.Equal(ToStringMapEnum.й, find.enum_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enum_to_string, ToStringMapEnum.).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum., find.enum_to_string); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enum_to_string, ToStringMapEnum.abc).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum.abc, find.enum_to_string); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.й).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.enum_to_string == ToStringMapEnum.abc).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void EnumNullable() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Null(find.enumnullable_to_string); + + item = new ToStringMap { enumnullable_to_string = ToStringMapEnum.й }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.й).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Equal(ToStringMapEnum.й, find.enumnullable_to_string); + + //update all + item.enumnullable_to_string = ToStringMapEnum.; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Equal(ToStringMapEnum., find.enumnullable_to_string); + + item.enumnullable_to_string = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.).First()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.enumnullable_to_string, find.enumnullable_to_string); + Assert.Null(find.enumnullable_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enumnullable_to_string, ToStringMapEnum.abc).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.abc).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(ToStringMapEnum.abc, find.enumnullable_to_string); + + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.enumnullable_to_string, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.abc).First()); + find = orm.Select().Where(a => a.id == item.id && a.enumnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.enumnullable_to_string); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.й).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_string == ToStringMapEnum.).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.enumnullable_to_string == null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void BigInteger1() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.biginteger_to_string == 0).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.biginteger_to_string, find.biginteger_to_string); + Assert.Equal(0, find.biginteger_to_string); + + item = new ToStringMap { biginteger_to_string = 100 }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.biginteger_to_string == 100).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.biginteger_to_string, find.biginteger_to_string); + Assert.Equal(100, find.biginteger_to_string); + + //update all + item.biginteger_to_string = 200; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.biginteger_to_string == 200).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.biginteger_to_string, find.biginteger_to_string); + Assert.Equal(200, find.biginteger_to_string); + + item.biginteger_to_string = 205; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.biginteger_to_string == 205).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.biginteger_to_string, find.biginteger_to_string); + Assert.Equal(205, find.biginteger_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.biginteger_to_string, 522).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.biginteger_to_string == 522).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(522, find.biginteger_to_string); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.biginteger_to_string, 10005).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.biginteger_to_string == 10005).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(10005, find.biginteger_to_string); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.biginteger_to_string == 522).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.biginteger_to_string == 205).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.biginteger_to_string == 10005).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void BigIntegerNullable() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.bigintegernullable_to_string, find.bigintegernullable_to_string); + Assert.Null(find.bigintegernullable_to_string); + + item = new ToStringMap { bigintegernullable_to_string = 101 }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == 101).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.bigintegernullable_to_string, find.bigintegernullable_to_string); + Assert.Equal(101, find.bigintegernullable_to_string); + + //update all + item.bigintegernullable_to_string = 2004; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == 2004).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.bigintegernullable_to_string, find.bigintegernullable_to_string); + Assert.Equal(2004, find.bigintegernullable_to_string); + + item.bigintegernullable_to_string = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == 2004).First()); + find = orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.bigintegernullable_to_string, find.bigintegernullable_to_string); + Assert.Null(find.bigintegernullable_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.bigintegernullable_to_string, 998).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == 998).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(998, find.bigintegernullable_to_string); + + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.bigintegernullable_to_string, null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == 998).First()); + find = orm.Select().Where(a => a.id == item.id && a.bigintegernullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.bigintegernullable_to_string); + + //delete + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.bigintegernullable_to_string == 998).ExecuteAffrows()); + Assert.Equal(0, orm.Delete().Where(a => a.id == item.id && a.bigintegernullable_to_string == 2004).ExecuteAffrows()); + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.bigintegernullable_to_string == null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void TimeSpan1() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespan_to_string, find.timespan_to_string); + Assert.Equal(TimeSpan.Zero, find.timespan_to_string); + + item = new ToStringMap { timespan_to_string = TimeSpan.FromDays(1) }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespan_to_string, find.timespan_to_string); + Assert.Equal(TimeSpan.FromDays(1), find.timespan_to_string); + + //update all + item.timespan_to_string = TimeSpan.FromHours(10); + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespan_to_string, find.timespan_to_string); + Assert.Equal(TimeSpan.FromHours(10), find.timespan_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.timespan_to_string, TimeSpan.FromHours(11)).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(TimeSpan.FromHours(11), find.timespan_to_string); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void TimeSpanNullable() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespannullable_to_string, find.timespannullable_to_string); + Assert.Null(find.timespannullable_to_string); + + item = new ToStringMap { timespannullable_to_string = TimeSpan.FromDays(1) }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespannullable_to_string, find.timespannullable_to_string); + Assert.Equal(TimeSpan.FromDays(1), find.timespannullable_to_string); + + //update all + item.timespannullable_to_string = TimeSpan.FromHours(10); + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespannullable_to_string, find.timespannullable_to_string); + Assert.Equal(TimeSpan.FromHours(10), find.timespannullable_to_string); + + item.timespannullable_to_string = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.timespannullable_to_string, find.timespannullable_to_string); + Assert.Null(find.timespannullable_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.timespannullable_to_string, TimeSpan.FromHours(11)).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(TimeSpan.FromHours(11), find.timespannullable_to_string); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.timespannullable_to_string, null).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.timespannullable_to_string); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void DateTime1() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetime_to_string, find.datetime_to_string); + Assert.Equal(DateTime.MinValue, find.datetime_to_string); + + item = new ToStringMap { datetime_to_string = DateTime.Parse("2000-1-1") }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetime_to_string, find.datetime_to_string); + Assert.Equal(DateTime.Parse("2000-1-1"), find.datetime_to_string); + + //update all + item.datetime_to_string = DateTime.Parse("2000-1-11"); + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetime_to_string, find.datetime_to_string); + Assert.Equal(DateTime.Parse("2000-1-11"), find.datetime_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.datetime_to_string, DateTime.Parse("2000-1-12")).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(DateTime.Parse("2000-1-12"), find.datetime_to_string); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void DateTimeNullable() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetimenullable_to_string, find.datetimenullable_to_string); + Assert.Null(find.datetimenullable_to_string); + + item = new ToStringMap { datetimenullable_to_string = DateTime.Parse("2000-1-1") }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetimenullable_to_string, find.datetimenullable_to_string); + Assert.Equal(DateTime.Parse("2000-1-1"), find.datetimenullable_to_string); + + //update all + item.datetimenullable_to_string = DateTime.Parse("2000-1-11"); + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetimenullable_to_string, find.datetimenullable_to_string); + Assert.Equal(DateTime.Parse("2000-1-11"), find.datetimenullable_to_string); + + item.datetimenullable_to_string = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.datetimenullable_to_string, find.datetimenullable_to_string); + Assert.Null(find.datetimenullable_to_string); + + //update set + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.datetimenullable_to_string, DateTime.Parse("2000-1-12")).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(DateTime.Parse("2000-1-12"), find.datetimenullable_to_string); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.datetimenullable_to_string, null).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.datetimenullable_to_string); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + + [Fact] + public void Guid1() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.guid_to_string == Guid.Empty).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guid_to_string, find.guid_to_string); + Assert.Equal(Guid.Empty, find.guid_to_string); + + var newid = Guid.NewGuid(); + item = new ToStringMap { guid_to_string = newid }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guid_to_string == newid).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guid_to_string, find.guid_to_string); + Assert.Equal(newid, find.guid_to_string); + + //update all + newid = Guid.NewGuid(); + item.guid_to_string = newid; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guid_to_string == newid).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guid_to_string, find.guid_to_string); + Assert.Equal(newid, find.guid_to_string); + + //update set + newid = Guid.NewGuid(); + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.guid_to_string, newid).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guid_to_string == newid).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(newid, find.guid_to_string); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.guid_to_string == newid).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + [Fact] + public void GuidNullable() + { + //insert + var orm = g.kingbaseES; + var item = new ToStringMap { }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + var find = orm.Select().Where(a => a.id == item.id && a.guidnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guidnullable_to_string, find.guidnullable_to_string); + Assert.Null(find.guidnullable_to_string); + + var newid = Guid.NewGuid(); + item = new ToStringMap { guidnullable_to_string = newid }; + Assert.Equal(1, orm.Insert().AppendData(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guidnullable_to_string == newid).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guidnullable_to_string, find.guidnullable_to_string); + Assert.Equal(newid, find.guidnullable_to_string); + + //update all + newid = Guid.NewGuid(); + item.guidnullable_to_string = newid; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guidnullable_to_string == newid).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guidnullable_to_string, find.guidnullable_to_string); + Assert.Equal(newid, find.guidnullable_to_string); + + item.guidnullable_to_string = null; + Assert.Equal(1, orm.Update().SetSource(item).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guidnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(item.guidnullable_to_string, find.guidnullable_to_string); + Assert.Null(find.guidnullable_to_string); + + //update set + newid = Guid.NewGuid(); + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.guidnullable_to_string, newid).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guidnullable_to_string == newid).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Equal(newid, find.guidnullable_to_string); + + Assert.Equal(1, orm.Update().Where(a => a.id == item.id).Set(a => a.guidnullable_to_string, null).ExecuteAffrows()); + find = orm.Select().Where(a => a.id == item.id && a.guidnullable_to_string == null).First(); + Assert.NotNull(find); + Assert.Equal(item.id, find.id); + Assert.Null(find.guidnullable_to_string); + + //delete + Assert.Equal(1, orm.Delete().Where(a => a.id == item.id && a.guidnullable_to_string == null).ExecuteAffrows()); + Assert.Null(orm.Select().Where(a => a.id == item.id).First()); + } + } +} diff --git a/FreeSql.Tests/FreeSql.Tests/g.cs b/FreeSql.Tests/FreeSql.Tests/g.cs index 7b814ff5..02e4b983 100644 --- a/FreeSql.Tests/FreeSql.Tests/g.cs +++ b/FreeSql.Tests/FreeSql.Tests/g.cs @@ -148,4 +148,18 @@ public class g .Build(); }); public static IFreeSql shentong => shentongLazy.Value; + + static Lazy kingbaseESLazy = new Lazy(() => new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.KingbaseES, "Server=127.0.0.1;Port=54321;UID=USER2;PWD=123456789;database=TDB2") + //.UseConnectionFactory(FreeSql.DataType.KingbaseES, () => new Kdbndp.KdbndpConnection("Server=127.0.0.1;Port=54321;UID=USER2;PWD=123456789;database=TDB2")) + .UseAutoSyncStructure(true) + .UseLazyLoading(true) + .UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper) + .UseNoneCommandParameter(true) + + .UseMonitorCommand( + cmd => Trace.WriteLine(cmd.CommandText), //监听SQL命令对象,在执行前 + (cmd, traceLog) => Console.WriteLine(traceLog)) + .Build()); + public static IFreeSql kingbaseES => kingbaseESLazy.Value; } diff --git a/FreeSql.sln b/FreeSql.sln index e1c05120..8ffb0633 100644 --- a/FreeSql.sln +++ b/FreeSql.sln @@ -86,6 +86,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests.Provider.Post EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.SqlServerForSystem", "Providers\FreeSql.Provider.SqlServerForSystem\FreeSql.Provider.SqlServerForSystem.csproj", "{3D2BD8EC-253A-437F-B4C8-74BC0D91429B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.KingbaseES", "Providers\FreeSql.Provider.KingbaseES\FreeSql.Provider.KingbaseES.csproj", "{CDD6A896-F6DF-44CB-B430-06B383916EB0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -528,6 +530,18 @@ Global {3D2BD8EC-253A-437F-B4C8-74BC0D91429B}.Release|x64.Build.0 = Release|Any CPU {3D2BD8EC-253A-437F-B4C8-74BC0D91429B}.Release|x86.ActiveCfg = Release|Any CPU {3D2BD8EC-253A-437F-B4C8-74BC0D91429B}.Release|x86.Build.0 = Release|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Debug|x64.ActiveCfg = Debug|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Debug|x64.Build.0 = Debug|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Debug|x86.ActiveCfg = Debug|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Debug|x86.Build.0 = Debug|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Release|Any CPU.Build.0 = Release|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Release|x64.ActiveCfg = Release|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Release|x64.Build.0 = Release|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Release|x86.ActiveCfg = Release|Any CPU + {CDD6A896-F6DF-44CB-B430-06B383916EB0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -558,6 +572,7 @@ Global {07AB0B37-A8B1-4FB1-9259-7B804E369E36} = {94C8A78D-AA15-47B2-A348-530CD86BFC1B} {938173AF-157F-4040-AED3-171DA1809CAA} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {3D2BD8EC-253A-437F-B4C8-74BC0D91429B} = {2A381C57-2697-427B-9F10-55DA11FD02E4} + {CDD6A896-F6DF-44CB-B430-06B383916EB0} = {2A381C57-2697-427B-9F10-55DA11FD02E4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} diff --git a/FreeSql/DataType.cs b/FreeSql/DataType.cs index 0d00c721..78f0d7cb 100644 --- a/FreeSql/DataType.cs +++ b/FreeSql/DataType.cs @@ -44,6 +44,11 @@ namespace FreeSql /// /// 天津神舟通用数据技术有限公司,基于 System.Data.OscarClient.dll 的实现 /// - ShenTong + ShenTong, + + /// + /// 北京人大金仓信息技术股份有限公司,基于 Kdbndp.dll 的实现 + /// + KingbaseES } } diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index 7ce20615..c90437a1 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -430,6 +430,7 @@ public static partial class FreeSqlGlobalExtensions { case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: //神通测试未通过 case DataType.SqlServer: @@ -487,6 +488,7 @@ public static partial class FreeSqlGlobalExtensions { case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: //神通测试未通过 case DataType.MySql: diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 1426df9f..a5622151 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -601,6 +601,11 @@ 天津神舟通用数据技术有限公司,基于 System.Data.OscarClient.dll 的实现 + + + 北京人大金仓信息技术股份有限公司,基于 Kdbndp.dll 的实现 + + 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null @@ -2613,6 +2618,145 @@ + + + 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 + + + + + + + + + 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + 查询 + + + + + + + 查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + 执行SQL返回对象集合,Query<User, Address>("select * from user where age > ?age; select * from address", new { age = 25 }) + 提示:parms 参数还可以传 Dictionary<string, object> + + + + + + 可自定义解析表达式 @@ -3349,6 +3493,12 @@ 超时 + + + 获取资源 + + + 使用完毕后,归还资源 @@ -3419,6 +3569,12 @@ 资源对象 + + + 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 + + 资源对象 + 归还对象给对象池的时候触发 diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index 58fc9ee8..727d0fc4 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -246,6 +246,11 @@ namespace FreeSql if (type == null) throwNotFind("FreeSql.Provider.ShenTong.dll", "FreeSql.ShenTong.ShenTongProvider<>"); break; + case DataType.KingbaseES: + type = Type.GetType("FreeSql.KingbaseES.KingbaseESProvider`1,FreeSql.Provider.KingbaseES")?.MakeGenericType(typeof(TMark)); + if (type == null) throwNotFind("FreeSql.Provider.KingbaseES.dll", "FreeSql.KingbaseES.KingbaseESProvider<>"); + break; + default: throw new Exception("未指定 UseConnectionString 或者 UseConnectionFactory"); } } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 153655e0..89c341d5 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -617,6 +617,7 @@ namespace FreeSql.Internal.CommonProvider break; case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: _tosqlAppendContent = $" for update{(noawait ? " nowait" : "")}"; break; diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index a90c057a..24aeb1f8 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -247,6 +247,7 @@ namespace FreeSql.Internal break; case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: if (strlen < 0) colattr.DbType = "TEXT"; @@ -295,6 +296,7 @@ namespace FreeSql.Internal break; case DataType.PostgreSQL: case DataType.OdbcPostgreSQL: + case DataType.KingbaseES: case DataType.OdbcKingbaseES: case DataType.ShenTong: //驱动引发的异常:“System.Data.OscarClient.OscarException”(位于 System.Data.OscarClient.dll 中) colattr.DbType = "BYTEA"; //变长二进制串 diff --git a/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESDelete.cs b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESDelete.cs new file mode 100644 index 00000000..8b9018e8 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESDelete.cs @@ -0,0 +1,99 @@ +using FreeSql.Internal; +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESDelete : Internal.CommonProvider.DeleteProvider where T1 : class + { + public KingbaseESDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) + : base(orm, commonUtils, commonExpression, dywhere) + { + } + + public override List ExecuteDeleted() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + var sb = new StringBuilder(); + sb.Append(sql).Append(" RETURNING "); + + var colidx = 0; + foreach (var col in _table.Columns.Values) + { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + sql = sb.ToString(); + var dbParms = _params.ToArray(); + var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + var ret = new List(); + Exception exception = null; + try + { + ret = _orm.Ado.Query(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, dbParms); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + this.ClearData(); + return ret; + } + +#if net40 +#else + async public override Task> ExecuteDeletedAsync() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + var sb = new StringBuilder(); + sb.Append(sql).Append(" RETURNING "); + + var colidx = 0; + foreach (var col in _table.Columns.Values) + { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + sql = sb.ToString(); + var dbParms = _params.ToArray(); + var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Delete, sql, dbParms); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + var ret = new List(); + Exception exception = null; + try + { + ret = await _orm.Ado.QueryAsync(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, dbParms); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + this.ClearData(); + return ret; + } +#endif + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsert.cs b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsert.cs new file mode 100644 index 00000000..f76a3683 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsert.cs @@ -0,0 +1,216 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESInsert : Internal.CommonProvider.InsertProvider where T1 : class + { + public KingbaseESInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) + : base(orm, commonUtils, commonExpression) + { + } + + internal IFreeSql InternalOrm => _orm; + internal TableInfo InternalTable => _table; + internal DbParameter[] InternalParams => _params; + internal DbConnection InternalConnection => _connection; + internal DbTransaction InternalTransaction => _transaction; + internal CommonUtils InternalCommonUtils => _commonUtils; + internal CommonExpression InternalCommonExpression => _commonExpression; + internal List InternalSource => _source; + internal Dictionary InternalIgnore => _ignore; + internal void InternalClearData() => ClearData(); + + public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + public override long ExecuteIdentity() => base.SplitExecuteIdentity(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + public override List ExecuteInserted() => base.SplitExecuteInserted(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + + protected override long RawExecuteIdentity() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return 0; + + long ret = 0; + Exception exception = null; + Aop.CurdBeforeEventArgs before = null; + + var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true); + if (identCols.Any() == false) + { + before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + try + { + ret = _orm.Ado.ExecuteNonQuery(_connection, _transaction, CommandType.Text, sql, _params); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return 0; + } + sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)); + before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + try + { + long.TryParse(string.Concat(_orm.Ado.ExecuteScalar(_connection, _transaction, CommandType.Text, sql, _params)), out ret); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return ret; + } + + protected override List RawExecuteInserted() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + var sb = new StringBuilder(); + sb.Append(sql).Append(" RETURNING "); + + var colidx = 0; + foreach (var col in _table.Columns.Values) + { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + sql = sb.ToString(); + var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + var ret = new List(); + Exception exception = null; + try + { + ret = _orm.Ado.Query(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _params); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return ret; + } + +#if net40 +#else + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + public override Task ExecuteIdentityAsync() => base.SplitExecuteIdentityAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + public override Task> ExecuteInsertedAsync() => base.SplitExecuteInsertedAsync(_batchValuesLimit > 0 ? _batchValuesLimit : 5000, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + + async protected override Task RawExecuteIdentityAsync() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return 0; + + long ret = 0; + Exception exception = null; + Aop.CurdBeforeEventArgs before = null; + + var identCols = _table.Columns.Where(a => a.Value.Attribute.IsIdentity == true); + if (identCols.Any() == false) + { + before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + try + { + ret = await _orm.Ado.ExecuteNonQueryAsync(_connection, _transaction, CommandType.Text, sql, _params); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return 0; + } + sql = string.Concat(sql, " RETURNING ", _commonUtils.QuoteSqlName(identCols.First().Value.Attribute.Name)); + before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + try + { + long.TryParse(string.Concat(await _orm.Ado.ExecuteScalarAsync(_connection, _transaction, CommandType.Text, sql, _params)), out ret); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return ret; + } + async protected override Task> RawExecuteInsertedAsync() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + var sb = new StringBuilder(); + sb.Append(sql).Append(" RETURNING "); + + var colidx = 0; + foreach (var col in _table.Columns.Values) + { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + sql = sb.ToString(); + var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, sql, _params); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + var ret = new List(); + Exception exception = null; + try + { + ret = await _orm.Ado.QueryAsync(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, _params); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return ret; + } +#endif + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsertOrUpdate.cs b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsertOrUpdate.cs new file mode 100644 index 00000000..6a4fd4a4 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsertOrUpdate.cs @@ -0,0 +1,57 @@ +using FreeSql.Internal; +using System.Collections.Generic; +using System.Data.Common; +using System.Linq; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESInsertOrUpdate : Internal.CommonProvider.InsertOrUpdateProvider where T1 : class + { + public KingbaseESInsertOrUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) + : base(orm, commonUtils, commonExpression) + { + } + + public override string ToSql() + { + if (_source?.Any() != true) return null; + + var sqls = new string[2]; + var dbParams = new List(); + var ds = SplitSourceByIdentityValueIsNull(_source); + if (ds.Item1.Any()) sqls[0] = getInsertSql(ds.Item1, false); + if (ds.Item2.Any()) sqls[1] = getInsertSql(ds.Item2, true); + _params = dbParams.ToArray(); + if (ds.Item2.Any() == false) return sqls[0]; + if (ds.Item1.Any() == false) return sqls[1]; + return string.Join("\r\n\r\n;\r\n\r\n", sqls); + + string getInsertSql(List data, bool flagInsert) + { + var insert = _orm.Insert() + .AsTable(_tableRule).AsType(_table.Type) + .WithConnection(_connection) + .WithTransaction(_transaction) + .NoneParameter(true) as Internal.CommonProvider.InsertProvider; + insert._source = data; + insert._noneParameterFlag = flagInsert ? "cuc" : "cu"; + + string sql = ""; + if (IdentityColumn != null && flagInsert) sql = insert.ToSql(); + else + { + var ocdu = new KingbaseESOnConflictDoUpdate(insert.InsertIdentity()); + var cols = _table.Columns.Values.Where(a => a.Attribute.IsPrimary == false && a.Attribute.CanUpdate == true && _updateIgnore.ContainsKey(a.Attribute.Name) == false); + ocdu.UpdateColumns(cols.Select(a => a.Attribute.Name).ToArray()); + if (_doNothing == true || cols.Any() == false) + ocdu.DoNothing(); + sql = ocdu.ToSql(); + } + if (string.IsNullOrEmpty(sql)) return null; + if (insert._params?.Any() == true) dbParams.AddRange(insert._params); + return sql; + } + } + } +} \ No newline at end of file diff --git a/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESOnConflictDoUpdate.cs b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESOnConflictDoUpdate.cs new file mode 100644 index 00000000..e1e55dd7 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESOnConflictDoUpdate.cs @@ -0,0 +1,208 @@ +using FreeSql.Aop; +using FreeSql.Internal.Model; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.KingbaseES +{ + public class KingbaseESOnConflictDoUpdate where T1 : class + { + internal KingbaseESInsert _insert; + internal KingbaseESUpdate _updatePriv; + internal KingbaseESUpdate _update => _updatePriv ?? + (_updatePriv = new KingbaseESUpdate(_insert.InternalOrm, _insert.InternalCommonUtils, _insert.InternalCommonExpression, null) { InternalTableAlias = "EXCLUDED" } + .NoneParameter().SetSource(_insert.InternalSource) as KingbaseESUpdate); + ColumnInfo[] _columns; + bool _doNothing; + + public KingbaseESOnConflictDoUpdate(IInsert insert, Expression> columns = null) + { + _insert = insert as KingbaseESInsert; + if (_insert == null) throw new Exception("OnConflictDoUpdate 是 FreeSql.Provider.KingbaseES 特有的功能"); + if (_insert._noneParameterFlag == "c") _insert._noneParameterFlag = "cu"; + + if (columns != null) + { + var colsList = new List(); + var cols = _insert.InternalCommonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).ToDictionary(a => a, a => true); + foreach (var col in _insert.InternalTable.Columns.Values) + if (cols.ContainsKey(col.Attribute.Name)) + colsList.Add(col); + _columns = colsList.ToArray(); + } + if (_columns == null || _columns.Any() == false) + _columns = _insert.InternalTable.Primarys; + if (_columns.Any() == false) throw new Exception("OnConflictDoUpdate 功能要求实体类必须设置 IsPrimary 属性"); + } + + protected void ClearData() + { + _insert.InternalClearData(); + _updatePriv = null; + } + + public KingbaseESOnConflictDoUpdate IgnoreColumns(Expression> columns) + { + _update.IgnoreColumns(columns); + return this; + } + public KingbaseESOnConflictDoUpdate UpdateColumns(Expression> columns) + { + _update.UpdateColumns(columns); + return this; + } + public KingbaseESOnConflictDoUpdate IgnoreColumns(string[] columns) + { + _update.IgnoreColumns(columns); + return this; + } + public KingbaseESOnConflictDoUpdate UpdateColumns(string[] columns) + { + _update.UpdateColumns(columns); + return this; + } + + public KingbaseESOnConflictDoUpdate Set(Expression> column, TMember value) + { + _update.Set(column, value); + return this; + } + //由于表达式解析问题,ON CONFLICT("id") DO UPDATE SET 需要指定表别名,如 Set(a => a.Clicks + 1) 解析会失败 + //暂时不开放这个功能,如有需要使用 SetRaw("click = t.click + 1") 替代该操作 + //public OnConflictDoUpdate Set(Expression> exp) + //{ + // _update.Set(exp); + // return this; + //} + public KingbaseESOnConflictDoUpdate SetRaw(string sql) + { + _update.SetRaw(sql); + return this; + } + + public KingbaseESOnConflictDoUpdate DoNothing() + { + _doNothing = true; + return this; + } + + public string ToSql() + { + var sb = new StringBuilder(); + sb.Append(_insert.ToSql()).Append("\r\nON CONFLICT("); + for (var a = 0; a < _columns.Length; a++) + { + if (a > 0) sb.Append(", "); + sb.Append(_insert.InternalCommonUtils.QuoteSqlName(_columns[a].Attribute.Name)); + } + if (_doNothing) + { + sb.Append(") DO NOTHING"); + } + else + { + sb.Append(") DO UPDATE SET\r\n"); + + var sbSetEmpty = _update.InternalSbSet.Length == 0; + var sbSetIncrEmpty = _update.InternalSbSetIncr.Length == 0; + if (sbSetEmpty == false || sbSetIncrEmpty == false) + { + if (sbSetEmpty == false) sb.Append(_update.InternalSbSet.ToString().Substring(2)); + if (sbSetIncrEmpty == false) sb.Append(sbSetEmpty ? _update.InternalSbSetIncr.ToString().Substring(2) : _update.InternalSbSetIncr.ToString()); + } + else + { + var colidx = 0; + foreach (var col in _insert.InternalTable.Columns.Values) + { + if (col.Attribute.IsPrimary || _update.InternalIgnore.ContainsKey(col.Attribute.Name)) continue; + + if (colidx > 0) sb.Append(", \r\n"); + + if (col.Attribute.IsVersion == true) + { + var field = _insert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name); + sb.Append(field).Append(" = ").Append(_insert.InternalCommonUtils.QuoteSqlName(_insert.InternalTable.DbName)).Append(".").Append(field).Append(" + 1"); + } + else if (_insert.InternalIgnore.ContainsKey(col.Attribute.Name)) + { + var caseWhen = _update.InternalWhereCaseSource(col.CsName, sqlval => sqlval).Trim(); + sb.Append(caseWhen); + if (caseWhen.EndsWith(" END")) _update.InternalToSqlCaseWhenEnd(sb, col); + } + else + { + var field = _insert.InternalCommonUtils.QuoteSqlName(col.Attribute.Name); + sb.Append(field).Append(" = EXCLUDED.").Append(field); + } + ++colidx; + } + } + } + + return sb.ToString(); + } + + public long ExecuteAffrows() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return 0; + + var before = new CurdBeforeEventArgs(_insert.InternalTable.Type, _insert.InternalTable, CurdType.Insert, sql, _insert.InternalParams); + _insert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_insert, before); + long ret = 0; + Exception exception = null; + try + { + ret = _insert.InternalOrm.Ado.ExecuteNonQuery(_insert.InternalConnection, _insert.InternalTransaction, CommandType.Text, sql, _insert.InternalParams); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new CurdAfterEventArgs(before, exception, ret); + _insert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_insert, after); + ClearData(); + } + return ret; + } + +#if net40 +#else + async public Task ExecuteAffrowsAsync() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return 0; + + var before = new CurdBeforeEventArgs(_insert.InternalTable.Type, _insert.InternalTable, CurdType.Insert, sql, _insert.InternalParams); + _insert.InternalOrm.Aop.CurdBeforeHandler?.Invoke(_insert, before); + long ret = 0; + Exception exception = null; + try + { + ret = await _insert.InternalOrm.Ado.ExecuteNonQueryAsync(_insert.InternalConnection, _insert.InternalTransaction, CommandType.Text, sql, _insert.InternalParams); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new CurdAfterEventArgs(before, exception, ret); + _insert.InternalOrm.Aop.CurdAfterHandler?.Invoke(_insert, after); + ClearData(); + } + return ret; + } +#endif + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESSelect.cs b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESSelect.cs new file mode 100644 index 00000000..fea0cca1 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESSelect.cs @@ -0,0 +1,174 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select1Provider where T1 : class + { + + internal static string ToSqlStatic(CommonUtils _commonUtils, CommonExpression _commonExpression, string _select, bool _distinct, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables, List> tbUnions, Func _aliasRule, string _tosqlAppendContent, List _whereCascadeExpression, IFreeSql _orm) + { + if (_orm.CodeFirst.IsAutoSyncStructure) + _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray()); + + if (_whereCascadeExpression.Any()) + foreach (var tb in _tables.Where(a => a.Type != SelectTableInfoType.Parent)) + tb.Cascade = _commonExpression.GetWhereCascadeSql(tb, _whereCascadeExpression, true); + + var sb = new StringBuilder(); + var tbUnionsGt0 = tbUnions.Count > 1; + for (var tbUnionsIdx = 0; tbUnionsIdx < tbUnions.Count; tbUnionsIdx++) + { + if (tbUnionsIdx > 0) sb.Append("\r\n \r\nUNION ALL\r\n \r\n"); + if (tbUnionsGt0) sb.Append(_select).Append(" * from ("); + var tbUnion = tbUnions[tbUnionsIdx]; + + var sbnav = new StringBuilder(); + sb.Append(_select); + if (_distinct) sb.Append("DISTINCT "); + sb.Append(field).Append(" \r\nFROM "); + var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray(); + var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray(); + for (var a = 0; a < tbsfrom.Length; a++) + { + sb.Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[a].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[a].Table.Type, tbsfrom[a].Alias) ?? tbsfrom[a].Alias); + if (tbsjoin.Length > 0) + { + //如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1 + for (var b = 1; b < tbsfrom.Length; b++) + { + sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbUnion[tbsfrom[b].Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tbsfrom[b].Table.Type, tbsfrom[b].Alias) ?? tbsfrom[b].Alias); + + if (string.IsNullOrEmpty(tbsfrom[b].NavigateCondition) && string.IsNullOrEmpty(tbsfrom[b].On) && string.IsNullOrEmpty(tbsfrom[b].Cascade)) sb.Append(" ON 1 = 1"); + else + { + var onSql = tbsfrom[b].NavigateCondition ?? tbsfrom[b].On; + sb.Append(" ON ").Append(onSql); + if (string.IsNullOrEmpty(tbsfrom[b].Cascade) == false) + { + if (string.IsNullOrEmpty(onSql)) sb.Append(tbsfrom[b].Cascade); + else sb.Append(" AND (").Append(tbsfrom[b].Cascade).Append(")"); + } + } + } + break; + } + else + { + if (!string.IsNullOrEmpty(tbsfrom[a].NavigateCondition)) sbnav.Append(" AND (").Append(tbsfrom[a].NavigateCondition).Append(")"); + if (!string.IsNullOrEmpty(tbsfrom[a].On)) sbnav.Append(" AND (").Append(tbsfrom[a].On).Append(")"); + if (a > 0 && !string.IsNullOrEmpty(tbsfrom[a].Cascade)) sbnav.Append(" AND (").Append(tbsfrom[a].Cascade).Append(")"); + } + if (a < tbsfrom.Length - 1) sb.Append(", "); + } + foreach (var tb in tbsjoin) + { + if (tb.Type == SelectTableInfoType.Parent) continue; + switch (tb.Type) + { + case SelectTableInfoType.LeftJoin: + sb.Append(" \r\nLEFT JOIN "); + break; + case SelectTableInfoType.InnerJoin: + sb.Append(" \r\nINNER JOIN "); + break; + case SelectTableInfoType.RightJoin: + sb.Append(" \r\nRIGHT JOIN "); + break; + } + sb.Append(_commonUtils.QuoteSqlName(tbUnion[tb.Table.Type])).Append(" ").Append(_aliasRule?.Invoke(tb.Table.Type, tb.Alias) ?? tb.Alias).Append(" ON ").Append(tb.On ?? tb.NavigateCondition); + if (!string.IsNullOrEmpty(tb.Cascade)) sb.Append(" AND (").Append(tb.Cascade).Append(")"); + if (!string.IsNullOrEmpty(tb.On) && !string.IsNullOrEmpty(tb.NavigateCondition)) sbnav.Append(" AND (").Append(tb.NavigateCondition).Append(")"); + } + if (_join.Length > 0) sb.Append(_join); + + sbnav.Append(_where); + if (!string.IsNullOrEmpty(_tables[0].Cascade)) + sbnav.Append(" AND (").Append(_tables[0].Cascade).Append(")"); + + if (sbnav.Length > 0) + { + sb.Append(" \r\nWHERE ").Append(sbnav.Remove(0, 5)); + } + if (string.IsNullOrEmpty(_groupby) == false) + { + sb.Append(_groupby); + if (string.IsNullOrEmpty(_having) == false) + sb.Append(" \r\nHAVING ").Append(_having.Substring(5)); + } + sb.Append(_orderby); + if (_limit > 0) + sb.Append(" \r\nlimit ").Append(_limit); + if (_skip > 0) + sb.Append(" \r\noffset ").Append(_skip); + + sbnav.Clear(); + if (tbUnionsGt0) sb.Append(") ftb"); + } + return sb.Append(_tosqlAppendContent).ToString(); + } + + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override ISelect From(Expression, T2, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression>> exp) { this.InternalFrom(exp); var ret = new KingbaseESSelect(_orm, _commonUtils, _commonExpression, null); KingbaseESSelect.CopyData(this, ret, exp?.Parameters); return ret; } + public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select3Provider where T1 : class where T2 : class where T3 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select4Provider where T1 : class where T2 : class where T3 : class where T4 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select5Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select6Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select7Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select8Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select9Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } + class KingbaseESSelect : FreeSql.Internal.CommonProvider.Select10Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class + { + public KingbaseESSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + public override string ToSql(string field = null) => KingbaseESSelect.ToSqlStatic(_commonUtils, _commonExpression, _select, _distinct, field ?? this.GetAllFieldExpressionTreeLevel2().Field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, this.GetTableRuleUnions(), _aliasRule, _tosqlAppendContent, _whereCascadeExpression, _orm); + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESUpdate.cs b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESUpdate.cs new file mode 100644 index 00000000..7b4428a8 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESUpdate.cs @@ -0,0 +1,169 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESUpdate : Internal.CommonProvider.UpdateProvider where T1 : class + { + + public KingbaseESUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) + : base(orm, commonUtils, commonExpression, dywhere) + { + } + + internal string InternalTableAlias { get; set; } + internal StringBuilder InternalSbSet => _set; + internal StringBuilder InternalSbSetIncr => _setIncr; + internal Dictionary InternalIgnore => _ignore; + internal void InternalResetSource(List source) => _source = source; + internal string InternalWhereCaseSource(string CsName, Func thenValue) => WhereCaseSource(CsName, thenValue); + internal void InternalToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) => ToSqlCaseWhenEnd(sb, col); + + public override int ExecuteAffrows() => base.SplitExecuteAffrows(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + public override List ExecuteUpdated() => base.SplitExecuteUpdated(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + + protected override List RawExecuteUpdated() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + var sb = new StringBuilder(); + sb.Append(sql).Append(" RETURNING "); + + var colidx = 0; + foreach (var col in _table.Columns.Values) + { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + sql = sb.ToString(); + var dbParms = _params.Concat(_paramsSource).ToArray(); + var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + var ret = new List(); + Exception exception = null; + try + { + ret = _orm.Ado.Query(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, dbParms); + ValidateVersionAndThrow(ret.Count, sql, dbParms); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return ret; + } + + protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) + { + if (_table.Primarys.Length == 1) + { + var pk = _table.Primarys.First(); + if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append("."); + caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))); + return; + } + caseWhen.Append("("); + var pkidx = 0; + foreach (var pk in _table.Primarys) + { + if (pkidx > 0) caseWhen.Append(" || '+' || "); + if (string.IsNullOrEmpty(InternalTableAlias) == false) caseWhen.Append(InternalTableAlias).Append("."); + caseWhen.Append(_commonUtils.QuoteReadColumn(pk.CsType, pk.Attribute.MapType, _commonUtils.QuoteSqlName(pk.Attribute.Name))).Append("::text"); + ++pkidx; + } + caseWhen.Append(")"); + } + + protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) + { + if (_table.Primarys.Length == 1) + { + sb.Append(_commonUtils.FormatSql("{0}", _table.Primarys[0].GetDbValue(d))); + return; + } + sb.Append("("); + var pkidx = 0; + foreach (var pk in _table.Primarys) + { + if (pkidx > 0) sb.Append(" || '+' || "); + sb.Append(_commonUtils.FormatSql("{0}", pk.GetDbValue(d))).Append("::text"); + ++pkidx; + } + sb.Append(")"); + } + + protected override void ToSqlCaseWhenEnd(StringBuilder sb, ColumnInfo col) + { + if (_noneParameter == false) return; + if (col.Attribute.MapType == typeof(string)) + { + sb.Append("::text"); + return; + } + var dbtype = _commonUtils.CodeFirst.GetDbInfo(col.Attribute.MapType)?.dbtype; + if (dbtype == null) return; + + sb.Append("::").Append(dbtype); + } + +#if net40 +#else + public override Task ExecuteAffrowsAsync() => base.SplitExecuteAffrowsAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + public override Task> ExecuteUpdatedAsync() => base.SplitExecuteUpdatedAsync(_batchRowsLimit > 0 ? _batchRowsLimit : 500, _batchParameterLimit > 0 ? _batchParameterLimit : 3000); + + async protected override Task> RawExecuteUpdatedAsync() + { + var sql = this.ToSql(); + if (string.IsNullOrEmpty(sql)) return new List(); + + var sb = new StringBuilder(); + sb.Append(sql).Append(" RETURNING "); + + var colidx = 0; + foreach (var col in _table.Columns.Values) + { + if (colidx > 0) sb.Append(", "); + sb.Append(_commonUtils.QuoteReadColumn(col.CsType, col.Attribute.MapType, _commonUtils.QuoteSqlName(col.Attribute.Name))).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); + ++colidx; + } + sql = sb.ToString(); + var dbParms = _params.Concat(_paramsSource).ToArray(); + var before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Update, sql, dbParms); + _orm.Aop.CurdBeforeHandler?.Invoke(this, before); + var ret = new List(); + Exception exception = null; + try + { + ret = await _orm.Ado.QueryAsync(_table.TypeLazy ?? _table.Type, _connection, _transaction, CommandType.Text, sql, dbParms); + ValidateVersionAndThrow(ret.Count, sql, dbParms); + } + catch (Exception ex) + { + exception = ex; + throw ex; + } + finally + { + var after = new Aop.CurdAfterEventArgs(before, exception, ret); + _orm.Aop.CurdAfterHandler?.Invoke(this, after); + } + return ret; + } +#endif + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/FreeSql.Provider.KingbaseES.csproj b/Providers/FreeSql.Provider.KingbaseES/FreeSql.Provider.KingbaseES.csproj new file mode 100644 index 00000000..a5aab1b8 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/FreeSql.Provider.KingbaseES.csproj @@ -0,0 +1,45 @@ + + + + netstandard2.0;net461 + 1.8.0-preview0820 + true + FreeSql;ncc;YeXiangQin + FreeSql 数据库实现,基于 人大金仓数据库 Ado.Net (Kdbndp) + https://github.com/2881099/FreeSql + https://github.com/2881099/FreeSql + git + MIT + FreeSql;ORM;人大金仓;金仓;Kdbndp + $(AssemblyName) + logo.png + $(AssemblyName) + true + true + + + + + + + + Always + + + + + + + + + + lib\Kdbndp.dll + false + + + + + ns20;netstandard20 + + + diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESAdo.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESAdo.cs new file mode 100644 index 00000000..a3f33988 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESAdo.cs @@ -0,0 +1,78 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using FreeSql.Internal.ObjectPool; +using Kdbndp; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data.Common; +using System.Text; +using System.Threading; + +namespace FreeSql.KingbaseES +{ + class KingbaseESAdo : FreeSql.Internal.CommonProvider.AdoProvider + { + public KingbaseESAdo() : base(DataType.KingbaseES, null, null) { } + public KingbaseESAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings, Func connectionFactory) : base(DataType.KingbaseES, masterConnectionString, slaveConnectionStrings) + { + base._util = util; + if (connectionFactory != null) + { + MasterPool = new FreeSql.Internal.CommonProvider.DbConnectionPool(DataType.KingbaseES, connectionFactory); + return; + } + if (!string.IsNullOrEmpty(masterConnectionString)) + MasterPool = new KingbaseESConnectionPool("主库", masterConnectionString, null, null); + if (slaveConnectionStrings != null) + { + foreach (var slaveConnectionString in slaveConnectionStrings) + { + var slavePool = new KingbaseESConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables)); + SlavePools.Add(slavePool); + } + } + } + public override object AddslashesProcessParam(object param, Type mapType, ColumnInfo mapColumn) + { + if (param == null) return "NULL"; + if (mapType != null && mapType != param.GetType() && (param is IEnumerable == false)) + param = Utils.GetDataReaderValue(mapType, param); + + if (param is bool || param is bool?) + return (bool)param ? "'t'" : "'f'"; + else if (param is string) + return string.Concat("'", param.ToString().Replace("'", "''"), "'"); + else if (param is char) + return string.Concat("'", param.ToString().Replace("'", "''").Replace('\0', ' '), "'"); + else if (param is Enum) + return ((Enum)param).ToInt64(); + else if (decimal.TryParse(string.Concat(param), out var trydec)) + return param; + else if (param is DateTime || param is DateTime?) + return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); + else if (param is TimeSpan || param is TimeSpan?) + return ((TimeSpan)param).Ticks / 10; + else if (param is byte[]) + return $"'\\x{CommonUtils.BytesSqlRaw(param as byte[])}'"; + else if (param is IEnumerable) + return AddslashesIEnumerable(param, mapType, mapColumn); + + return string.Concat("'", param.ToString().Replace("'", "''"), "'"); + } + + protected override DbCommand CreateCommand() + { + return new KdbndpCommand(); + } + + protected override void ReturnConnection(IObjectPool pool, Object conn, Exception ex) + { + var rawPool = pool as KingbaseESConnectionPool; + if (rawPool != null) rawPool.Return(conn, ex); + else pool.Return(conn); + } + + protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj); + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESConnectionPool.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESConnectionPool.cs new file mode 100644 index 00000000..44e2b2e9 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESAdo/KingbaseESConnectionPool.cs @@ -0,0 +1,258 @@ +using FreeSql.Internal.ObjectPool; +using Kdbndp; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESConnectionPool : ObjectPool + { + + internal Action availableHandler; + internal Action unavailableHandler; + internal string UserId { get; set; } + + public KingbaseESConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null) + { + this.UserId = KingbaseESConnectionPool.GetUserId(connectionString); + + this.availableHandler = availableHandler; + this.unavailableHandler = unavailableHandler; + var policy = new KingbaseESConnectionPoolPolicy + { + _pool = this, + Name = name + }; + this.Policy = policy; + policy.ConnectionString = connectionString; + } + + public static string GetUserId(string connectionString) + { + var userIdMatch = Regex.Match(connectionString, @"(User\s+Id|Uid)\s*=\s*([^;]+)", RegexOptions.IgnoreCase); + if (userIdMatch.Success == false) throw new Exception(@"从 ConnectionString 中无法匹配 (User\s+Id|Uid)\s*=\s*([^;]+)"); + return userIdMatch.Groups[2].Value.Trim().ToUpper(); + } + + public void Return(Object obj, Exception exception, bool isRecreate = false) + { + if (exception != null && exception is KdbndpException) + { + + if (exception is System.IO.IOException) + { + + base.SetUnavailable(exception); + + } + else if (obj.Value.Ping() == false) + { + + base.SetUnavailable(exception); + } + } + base.Return(obj, isRecreate); + } + } + + class KingbaseESConnectionPoolPolicy : IPolicy + { + + internal KingbaseESConnectionPool _pool; + public string Name { get; set; } = "KingbaseES KdbndpConnection 对象池"; + public int PoolSize { get; set; } = 100; + public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(20); + public int AsyncGetCapacity { get; set; } = 10000; + public bool IsThrowGetTimeoutException { get; set; } = true; + public bool IsAutoDisposeWithSystem { get; set; } = true; + public int CheckAvailableInterval { get; set; } = 5; + + static ConcurrentDictionary dicConnStrIncr = new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase); + private string _connectionString; + public string ConnectionString + { + get => _connectionString; + set + { + _connectionString = value ?? ""; + + var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)"; + Match m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100; + var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => Math.Min(5, oldval + 1)); + PoolSize = poolsize + connStrIncr; + _connectionString = m.Success ? + Regex.Replace(_connectionString, pattern, $"MaxPoolSize={PoolSize}", RegexOptions.IgnoreCase) : + $"{_connectionString};MaxPoolSize={PoolSize}"; + + pattern = @"Connection\s*LifeTime\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) + { + IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value)); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } + + var minPoolSize = 0; + pattern = @"Min\s*pool\s*size\s*=\s*(\d+)"; + m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase); + if (m.Success) + { + minPoolSize = int.Parse(m.Groups[1].Value); + _connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase); + } + + FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize); + } + } + + public bool OnCheckAvailable(Object obj) + { + if (obj.Value.State == ConnectionState.Closed) obj.Value.Open(); + return obj.Value.Ping(true); + } + + public DbConnection OnCreate() + { + var conn = new KdbndpConnection(_connectionString); + return conn; + } + + public void OnDestroy(DbConnection obj) + { + if (obj.State != ConnectionState.Closed) obj.Close(); + obj.Dispose(); + } + + public void OnGet(Object obj) + { + + if (_pool.IsAvailable) + { + if (obj.Value == null) + { + if (_pool.SetUnavailable(new Exception("连接字符串错误")) == true) + throw new Exception($"【{this.Name}】连接字符串错误,请检查。"); + return; + } + + if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) + { + + try + { + obj.Value.Open(); + } + catch (Exception ex) + { + if (_pool.SetUnavailable(ex) == true) + throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}"); + } + } + } + } + +#if net40 +#else + async public Task OnGetAsync(Object obj) + { + + if (_pool.IsAvailable) + { + if (obj.Value == null) + { + if (_pool.SetUnavailable(new Exception("连接字符串错误")) == true) + throw new Exception($"【{this.Name}】连接字符串错误,请检查。"); + return; + } + + if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false) + { + + try + { + await obj.Value.OpenAsync(); + } + catch (Exception ex) + { + if (_pool.SetUnavailable(ex) == true) + throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}"); + } + } + } + } +#endif + + public void OnGetTimeout() + { + + } + + public void OnReturn(Object obj) + { + //if (obj?.Value != null && obj.Value.State != ConnectionState.Closed) try { obj.Value.Close(); } catch { } + } + + public void OnAvailable() + { + _pool.availableHandler?.Invoke(); + } + + public void OnUnavailable() + { + _pool.unavailableHandler?.Invoke(); + } + } + + static class DbConnectionExtensions + { + + static DbCommand PingCommand(DbConnection conn) + { + var cmd = conn.CreateCommand(); + cmd.CommandTimeout = 5; + cmd.CommandText = "select 1"; + return cmd; + } + public static bool Ping(this DbConnection that, bool isThrow = false) + { + try + { + PingCommand(that).ExecuteNonQuery(); + return true; + } + catch + { + if (that.State != ConnectionState.Closed) try { that.Close(); } catch { } + if (isThrow) throw; + return false; + } + } + +#if net40 +#else + async public static Task PingAsync(this DbConnection that, bool isThrow = false) + { + try + { + await PingCommand(that).ExecuteNonQueryAsync(); + return true; + } + catch + { + if (that.State != ConnectionState.Closed) try { that.Close(); } catch { } + if (isThrow) throw; + return false; + } + } +#endif + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESCodeFirst.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESCodeFirst.cs new file mode 100644 index 00000000..b641c526 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESCodeFirst.cs @@ -0,0 +1,397 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using KdbndpTypes; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESCodeFirst : Internal.CommonProvider.CodeFirstProvider + { + public KingbaseESCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) : base(orm, commonUtils, commonExpression) { } + + static object _dicCsToDbLock = new object(); + static Dictionary> _dicCsToDb = new Dictionary>() { + { typeof(sbyte).FullName, CsToDb.New(KdbndpDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(sbyte?).FullName, CsToDb.New(KdbndpDbType.Smallint, "int2", "int2", false, true, null) }, + { typeof(short).FullName, CsToDb.New(KdbndpDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(short?).FullName, CsToDb.New(KdbndpDbType.Smallint, "int2", "int2", false, true, null) }, + { typeof(int).FullName, CsToDb.New(KdbndpDbType.Integer, "int4","int4 NOT NULL", false, false, 0) },{ typeof(int?).FullName, CsToDb.New(KdbndpDbType.Integer, "int4", "int4", false, true, null) }, + { typeof(long).FullName, CsToDb.New(KdbndpDbType.Bigint, "int8","int8 NOT NULL", false, false, 0) },{ typeof(long?).FullName, CsToDb.New(KdbndpDbType.Bigint, "int8", "int8", false, true, null) }, + + { typeof(byte).FullName, CsToDb.New(KdbndpDbType.Smallint, "int2","int2 NOT NULL", false, false, 0) },{ typeof(byte?).FullName, CsToDb.New(KdbndpDbType.Smallint, "int2", "int2", false, true, null) }, + { typeof(ushort).FullName, CsToDb.New(KdbndpDbType.Integer, "int4","int4 NOT NULL", false, false, 0) },{ typeof(ushort?).FullName, CsToDb.New(KdbndpDbType.Integer, "int4", "int4", false, true, null) }, + { typeof(uint).FullName, CsToDb.New(KdbndpDbType.Bigint, "int8","int8 NOT NULL", false, false, 0) },{ typeof(uint?).FullName, CsToDb.New(KdbndpDbType.Bigint, "int8", "int8", false, true, null) }, + { typeof(ulong).FullName, CsToDb.New(KdbndpDbType.Numeric, "numeric","numeric(20,0) NOT NULL", false, false, 0) },{ typeof(ulong?).FullName, CsToDb.New(KdbndpDbType.Numeric, "numeric", "numeric(20,0)", false, true, null) }, + + { typeof(float).FullName, CsToDb.New(KdbndpDbType.Real, "float4","float4 NOT NULL", false, false, 0) },{ typeof(float?).FullName, CsToDb.New(KdbndpDbType.Real, "float4", "float4", false, true, null) }, + { typeof(double).FullName, CsToDb.New(KdbndpDbType.Double, "float8","float8 NOT NULL", false, false, 0) },{ typeof(double?).FullName, CsToDb.New(KdbndpDbType.Double, "float8", "float8", false, true, null) }, + { typeof(decimal).FullName, CsToDb.New(KdbndpDbType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false, 0) },{ typeof(decimal?).FullName, CsToDb.New(KdbndpDbType.Numeric, "numeric", "numeric(10,2)", false, true, null) }, + + { typeof(string).FullName, CsToDb.New(KdbndpDbType.Varchar, "varchar", "varchar(255)", false, null, "") }, + { typeof(char).FullName, CsToDb.New(KdbndpDbType.Char, "bpchar", "bpchar(1) NULL", false, null, '\0') }, + + { typeof(TimeSpan).FullName, CsToDb.New(KdbndpDbType.Time, "time","time NOT NULL", false, false, 0) },{ typeof(TimeSpan?).FullName, CsToDb.New(KdbndpDbType.Time, "time", "time",false, true, null) }, + { typeof(DateTime).FullName, CsToDb.New(KdbndpDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false, new DateTime(1970,1,1)) },{ typeof(DateTime?).FullName, CsToDb.New(KdbndpDbType.Timestamp, "timestamp", "timestamp", false, true, null) }, + + { typeof(bool).FullName, CsToDb.New(KdbndpDbType.Bit, "bool","bool NOT NULL", null, false, false) },{ typeof(bool?).FullName, CsToDb.New(KdbndpDbType.Bit, "bool","bool", null, true, null) }, + { typeof(Byte[]).FullName, CsToDb.New(KdbndpDbType.Bytea, "bytea", "bytea", false, null, new byte[0]) }, + + { typeof(Guid).FullName, CsToDb.New(KdbndpDbType.Uuid, "uuid", "uuid NOT NULL", false, false, Guid.Empty) },{ typeof(Guid?).FullName, CsToDb.New(KdbndpDbType.Uuid, "uuid", "uuid", false, true, null) }, + }; + + public override DbInfoResult GetDbInfo(Type type) + { + if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new DbInfoResult((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable, trydc.defaultValue); + if (type.IsArray) return null; + var enumType = type.IsEnum ? type : null; + if (enumType == null && type.IsNullableType()) + { + var genericTypes = type.GetGenericArguments(); + if (genericTypes.Length == 1 && genericTypes.First().IsEnum) enumType = genericTypes.First(); + } + if (enumType != null) + { + var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ? + CsToDb.New(KdbndpDbType.Bigint, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()) : + CsToDb.New(KdbndpDbType.Integer, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true, enumType.CreateInstanceGetDefaultValue()); + if (_dicCsToDb.ContainsKey(type.FullName) == false) + { + lock (_dicCsToDbLock) + { + if (_dicCsToDb.ContainsKey(type.FullName) == false) + _dicCsToDb.Add(type.FullName, newItem); + } + } + return new DbInfoResult((int)newItem.type, newItem.dbtype, newItem.dbtypeFull, newItem.isnullable, newItem.defaultValue); + } + return null; + } + + protected override string GetComparisonDDLStatements(params TypeAndName[] objects) + { + var sb = new StringBuilder(); + var seqcols = new List>(); //序列 + + foreach (var obj in objects) + { + if (sb.Length > 0) sb.Append("\r\n"); + var tb = _commonUtils.GetTableByEntity(obj.entityType); + if (tb == null) throw new Exception($"类型 {obj.entityType.FullName} 不可迁移"); + if (tb.Columns.Any() == false) throw new Exception($"类型 {obj.entityType.FullName} 不可迁移,可迁移属性0个"); + var tbname = _commonUtils.SplitTableName(tb.DbName); + if (tbname?.Length == 1) tbname = new[] { "PUBLIC", tbname[0] }; + + var tboldname = _commonUtils.SplitTableName(tb.DbOldName); //旧表名 + if (tboldname?.Length == 1) tboldname = new[] { "PUBLIC", tboldname[0] }; + if (string.IsNullOrEmpty(obj.tableName) == false) + { + var tbtmpname = _commonUtils.SplitTableName(obj.tableName); + if (tbtmpname?.Length == 1) tbtmpname = new[] { "PUBLIC", tbtmpname[0] }; + if (tbname[0] != tbtmpname[0] || tbname[1] != tbtmpname[1]) + { + tbname = tbtmpname; + tboldname = null; + } + } + //codefirst 不支持表名、模式名、数据库名中带 . + + if (string.Compare(tbname[0], "PUBLIC", true) != 0 && _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(" select 1 from sys_namespace where nspname={0}", tbname[0])) == null) //创建模式 + sb.Append("CREATE SCHEMA IF NOT EXISTS ").Append(tbname[0]).Append(";\r\n"); + + var sbalter = new StringBuilder(); + var istmpatler = false; //创建临时表,导入数据,删除旧表,修改 + if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from sys_tables a inner join sys_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tbname)) == null) + { //表不存在 + if (tboldname != null) + { + if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format(" select 1 from sys_tables a inner join sys_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{0}.{1}'", tboldname)) == null) + //旧表不存在 + tboldname = null; + } + if (tboldname == null) + { + //创建表 + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); + foreach (var tbcol in tb.ColumnsByPosition) + { + sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); + if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, true)); + } + if (tb.Primarys.Any()) + { + var pkname = $"{tbname[0]}_{tbname[1]}_PKEY"; + sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY ("); + foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + sb.Remove(sb.Length - 2, 2).Append("),"); + } + sb.Remove(sb.Length - 1, 1); + sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } + //备注 + foreach (var tbcol in tb.ColumnsByPosition) + { + if (string.IsNullOrEmpty(tbcol.Comment) == false) + sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n"); + } + if (string.IsNullOrEmpty(tb.Comment) == false) + sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n"); + continue; + } + //如果新表,旧表在一个数据库和模式下,直接修改表名 + if (string.Compare(tbname[0], tboldname[0], true) == 0) + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append(";\r\n"); + else + { + //如果新表,旧表不在一起,创建新表,导入数据,删除旧表 + istmpatler = true; + } + } + else + tboldname = null; //如果新表已经存在,不走改表名逻辑 + + //对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段 + var sql = _commonUtils.FormatSql(@" +select +a.attname, +t.typname, +case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len, +case when t.typelem > 0 and t.typinput::varchar = 'ARRAY_IN' then t2.typname else t.typname end, +case when a.attnotnull then '0' else '1' end as is_nullable, +--e.adsrc, +(select sys_get_expr(adbin, adrelid) from sys_attrdef where adrelid = e.adrelid limit 1) is_identity, +a.attndims, +d.description as comment +from sys_class c +inner join sys_attribute a on a.attnum > 0 and a.attrelid = c.oid +inner join sys_type t on t.oid = a.atttypid +left join sys_type t2 on t2.oid = t.typelem +left join sys_description d on d.objoid = a.attrelid and d.objsubid = a.attnum +left join sys_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum +inner join sys_namespace ns on ns.oid = c.relnamespace +inner join sys_namespace ns2 on ns2.oid = t.typnamespace +where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname); + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + var tbstruct = ds.ToDictionary(a => string.Concat(a[0]), a => + { + var attndims = int.Parse(string.Concat(a[6])); + var type = string.Concat(a[1]); + var sqlType = string.Concat(a[3]); + var max_length = long.Parse(string.Concat(a[2])); + switch (sqlType.ToLower()) + { + case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break; + default: max_length *= 8; break; + } + if (type.StartsWith("_")) + { + type = type.Substring(1); + if (attndims == 0) attndims++; + } + if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1); + return new + { + column = string.Concat(a[0]), + sqlType = string.Concat(sqlType), + max_length = long.Parse(string.Concat(a[2])), + is_nullable = string.Concat(a[4]) == "1", + is_identity = string.Concat(a[5]).StartsWith(@"NEXTVAL('") && (string.Concat(a[5]).EndsWith(@"'::REGCLASS)") || string.Concat(a[5]).EndsWith(@"')")), + attndims, + comment = string.Concat(a[7]) + }; + }, StringComparer.CurrentCultureIgnoreCase); + + if (istmpatler == false) + { + foreach (var tbcol in tb.ColumnsByPosition) + { + if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) || + string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol)) + { + var isCommentChanged = tbstructcol.comment != (tbcol.Comment ?? ""); + if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false || + tbcol.Attribute.DbType.Contains("[]") != (tbstructcol.attndims > 0)) + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TYPE ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n"); + if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable) + { + if (tbcol.Attribute.IsNullable != true || tbcol.Attribute.IsNullable == true && tbcol.Attribute.IsPrimary == false) + { + if (tbcol.Attribute.IsNullable == false) + sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" = ").Append(tbcol.DbDefaultValue).Append(" WHERE ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" IS NULL;\r\n"); + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" ").Append(tbcol.Attribute.IsNullable == true ? "DROP" : "SET").Append(" NOT NULL;\r\n"); + } + } + if (tbcol.Attribute.IsIdentity != tbstructcol.is_identity) + seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true)); + if (string.Compare(tbstructcol.column, tbcol.Attribute.OldName, true) == 0) + //修改列名 + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(tbstructcol.column)).Append(" TO ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(";\r\n"); + if (isCommentChanged) + sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n"); + continue; + } + //添加列 + sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.Split(' ').First()).Append(";\r\n"); + sbalter.Append("UPDATE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" SET ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" = ").Append(tbcol.DbDefaultValue).Append(";\r\n"); + if (tbcol.Attribute.IsNullable == false) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" SET NOT NULL;\r\n"); + if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, tbcol.Attribute.IsIdentity == true)); + if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n"); + } + var dsuksql = _commonUtils.FormatSql(@" +select +c.attname, +b.relname, +case when sys_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, +case when indisunique = 't' then 1 else 0 end IsUnique +from sys_index a +inner join sys_class b on b.oid = a.indexrelid +inner join sys_attribute c on c.attnum > 0 and c.attrelid = b.oid +inner join sys_namespace ns on ns.oid = b.relnamespace +inner join sys_class d on d.oid = a.indrelid +where ns.nspname in ({0}) and d.relname in ({1}) and a.indisprimary = 'f'", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) + { + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var ukname = ReplaceIndexName(uk.Name, tbname[1]); + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) + { + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } + sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); + } + } + } + if (istmpatler == false) + { + var dbcomment = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select +d.description +from sys_class a +inner join sys_namespace b on b.oid = a.relnamespace +left join sys_description d on d.objoid = a.oid and objsubid = 0 +where b.nspname not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') and a.relkind in ('r') and b.nspname = {0} and a.relname = {1} +and b.nspname || '.' || a.relname not in ('PUBLIC.GEOGRAPHY_COLUMNS','PUBLIC.GEOMETRY_COLUMNS','PUBLIC.RASTER_COLUMNS','PUBLIC.RASTER_OVERVIEWS')", tbname[0], tbname[1]))); + if (dbcomment != (tb.Comment ?? "")) + sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n"); + + sb.Append(sbalter); + continue; + } + var oldpk = _orm.Ado.ExecuteScalar(CommandType.Text, _commonUtils.FormatSql(@" select sys_constraint.conname as pk_name from sys_constraint +inner join sys_class on sys_constraint.conrelid = sys_class.oid +inner join sys_namespace on sys_namespace.oid = sys_class.relnamespace +where sys_namespace.nspname={0} and sys_class.relname={1} and sys_constraint.contype='p' +", tbname))?.ToString(); + if (string.IsNullOrEmpty(oldpk) == false) + sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(oldpk).Append(";\r\n"); + + //创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名 + var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}"); + var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}"); + //创建临时表 + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(tmptablename).Append(" ( "); + foreach (var tbcol in tb.ColumnsByPosition) + { + sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); + if (tbcol.Attribute.IsIdentity == true) seqcols.Add(NativeTuple.Create(tbcol, tbname, true)); + } + if (tb.Primarys.Any()) + { + var pkname = $"{tbname[0]}_{tbname[1]}_pkey"; + sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(pkname)).Append(" PRIMARY KEY ("); + foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + sb.Remove(sb.Length - 2, 2).Append("),"); + } + sb.Remove(sb.Length - 1, 1); + sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); + //备注 + foreach (var tbcol in tb.ColumnsByPosition) + { + if (string.IsNullOrEmpty(tbcol.Comment) == false) + sb.Append("COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment)).Append(";\r\n"); + } + if (string.IsNullOrEmpty(tb.Comment) == false) + sb.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.FTmp_{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n"); + + sb.Append("INSERT INTO ").Append(tmptablename).Append(" ("); + foreach (var tbcol in tb.ColumnsByPosition) + sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + sb.Remove(sb.Length - 2, 2).Append(")\r\nSELECT "); + foreach (var tbcol in tb.ColumnsByPosition) + { + var insertvalue = "NULL"; + if (tbstruct.TryGetValue(tbcol.Attribute.Name, out var tbstructcol) || + string.IsNullOrEmpty(tbcol.Attribute.OldName) == false && tbstruct.TryGetValue(tbcol.Attribute.OldName, out tbstructcol)) + { + insertvalue = _commonUtils.QuoteSqlName(tbstructcol.column); + if (tbcol.Attribute.DbType.StartsWith(tbstructcol.sqlType, StringComparison.CurrentCultureIgnoreCase) == false) + insertvalue = $"cast({insertvalue} as {tbcol.Attribute.DbType.Split(' ').First()})"; + if (tbcol.Attribute.IsNullable != tbstructcol.is_nullable) + insertvalue = $"coalesce({insertvalue},{tbcol.DbDefaultValue})"; + } + else if (tbcol.Attribute.IsNullable == false) + insertvalue = tbcol.DbDefaultValue; + sb.Append(insertvalue).Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n"); + sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); + sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ReplaceIndexName(uk.Name, tbname[1]))).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } + } + foreach (var seqcol in seqcols) + { + var tbname = seqcol.Item2; + var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_seq").ToUpper(); ; + var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name); + sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT null;\r\n"); + sb.Append("DROP SEQUENCE IF EXISTS ").Append(seqname).Append(";\r\n"); + if (seqcol.Item3) + { + sb.Append("CREATE SEQUENCE ").Append(seqname).Append(";\r\n"); + sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT NEXTVAL('").Append(seqname).Append("'::REGCLASS);\r\n"); + sb.Append(" SELECT case when max(").Append(colname2).Append(") is null then 0 else setval('").Append(seqname).Append("', max(").Append(colname2).Append(")) end FROM ").Append(tbname2).Append(";\r\n"); + } + } + return sb.Length == 0 ? null : sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESDbFirst.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESDbFirst.cs new file mode 100644 index 00000000..bf079acd --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESDbFirst.cs @@ -0,0 +1,524 @@ +using FreeSql.DatabaseModel; +using FreeSql.Internal; +using FreeSql.Internal.Model; +using KdbndpTypes; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace FreeSql.KingbaseES +{ + class KingbaseESDbFirst : IDbFirst + { + IFreeSql _orm; + protected CommonUtils _commonUtils; + protected CommonExpression _commonExpression; + public KingbaseESDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) + { + _orm = orm; + _commonUtils = commonUtils; + _commonExpression = commonExpression; + } + + public int GetDbType(DbColumnInfo column) => (int)GetSqlDbType(column); + KdbndpDbType GetSqlDbType(DbColumnInfo column) + { + var dbtype = column.DbTypeText; + var isarray = dbtype.EndsWith("[]"); + if (isarray) dbtype = dbtype.Remove(dbtype.Length - 2); + var ret = KdbndpDbType.Unknown; + switch (dbtype.ToLower().TrimStart('_')) + { + case "tinyint": ret = KdbndpDbType.Smallint; break; + case "int2": ret = KdbndpDbType.Smallint; break; + case "int4": ret = KdbndpDbType.Integer; break; + case "int8": ret = KdbndpDbType.Bigint; break; + case "numeric": ret = KdbndpDbType.Numeric; break; + case "float4": ret = KdbndpDbType.Real; break; + case "float8": ret = KdbndpDbType.Double; break; + case "money": ret = KdbndpDbType.Money; break; + + case "char": ret = column.MaxLength == 36 ? KdbndpDbType.Uuid : KdbndpDbType.Char; break; + case "bpchar": ret = KdbndpDbType.Char; break; + case "varchar": ret = KdbndpDbType.Varchar; break; + case "text": ret = KdbndpDbType.Text; break; + + case "timestamp": ret = KdbndpDbType.Timestamp; break; + case "timestamptz": ret = KdbndpDbType.Timestamp; break; + case "date": ret = KdbndpDbType.Date; break; + case "time": ret = KdbndpDbType.Time; break; + case "timetz": ret = KdbndpDbType.Time; break; + case "interval": ret = KdbndpDbType.Time; break; + + case "bool": ret = KdbndpDbType.Bit; break; + case "blob": ret = KdbndpDbType.Bytea; break; + case "bytea": ret = KdbndpDbType.Bytea; break; + case "bit": ret = KdbndpDbType.Bit; break; + case "varbit": ret = KdbndpDbType.Varbit; break; + + case "uuid": ret = KdbndpDbType.Uuid; break; + } + return ret; + } + + static ConcurrentDictionary _dicDbToCs = new ConcurrentDictionary(); + static KingbaseESDbFirst() + { + var defaultDbToCs = new Dictionary() { + { (int)KdbndpDbType.Smallint, new DbToCs("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(int), typeof(int?), "{0}.Value", "GetInt16") }, + { (int)KdbndpDbType.Integer, new DbToCs("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(long), typeof(long?), "{0}.Value", "GetInt32") }, + { (int)KdbndpDbType.Bigint, new DbToCs("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") }, + { (int)KdbndpDbType.Real, new DbToCs("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") }, + { (int)KdbndpDbType.Double, new DbToCs("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") }, + { (int)KdbndpDbType.Numeric, new DbToCs("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, + + { (int)KdbndpDbType.Char, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)KdbndpDbType.Varchar, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + { (int)KdbndpDbType.Text, new DbToCs("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, + + { (int)KdbndpDbType.Timestamp, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)KdbndpDbType.Date, new DbToCs("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") }, + { (int)KdbndpDbType.Time, new DbToCs("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") }, + + { (int)KdbndpDbType.Bit, new DbToCs("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") }, + { (int)KdbndpDbType.Bytea, new DbToCs("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") }, + + { (int)KdbndpDbType.Uuid, new DbToCs("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid", typeof(Guid), typeof(Guid?), "{0}", "GetString") }, + }; + foreach (var kv in defaultDbToCs) + _dicDbToCs.TryAdd(kv.Key, kv.Value); + } + + public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null; + public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null; + public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null; + public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null; + public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null; + public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null; + public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null; + + public List GetDatabases() + { + var sql = @" select datname from sys_database where datname not in ('TEMPLATE1', 'TEMPLATE0', 'TEMPLATE2')"; + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList(); + } + + public bool ExistsTable(string name, bool ignoreCase) + { + if (string.IsNullOrEmpty(name)) return false; + var tbname = _commonUtils.SplitTableName(name); + if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] }; + if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray(); + var sql = $" select 1 from sys_tables a inner join sys_namespace b on b.nspname = a.schemaname where {(ignoreCase ? "lower(b.nspname)" : "b.nspname")}={_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(a.tablename)" : "a.tablename")}={_commonUtils.FormatSql("{0}", tbname[1])}"; + return string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, sql)) == "1"; + } + + public DbTableInfo GetTableByName(string name, bool ignoreCase = true) => GetTables(null, name, ignoreCase)?.FirstOrDefault(); + public List GetTablesByDatabase(params string[] database) => GetTables(database, null, false); + + public List GetTables(string[] database, string tablename, bool ignoreCase) + { + var olddatabase = ""; + using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) + { + olddatabase = conn.Value.Database; + } + string[] tbname = null; + string[] dbs = database == null || database.Any() == false ? new[] { olddatabase } : database; + if (string.IsNullOrEmpty(tablename) == false) + { + tbname = _commonUtils.SplitTableName(tablename); + if (tbname?.Length == 1) tbname = new[] { "public", tbname[0] }; + if (ignoreCase) tbname = tbname.Select(a => a.ToLower()).ToArray(); + dbs = new[] { olddatabase }; + } + + var tables = new List(); + foreach (var db in dbs) + { + if (string.IsNullOrEmpty(db) || string.Compare(db, olddatabase, true) != 0) continue; + + var loc1 = new List(); + var loc2 = new Dictionary(); + var loc3 = new Dictionary>(); + + var sql = $@" +{(tbname == null ? "" : $"select * from (")}select +b.nspname || '.' || a.tablename, +a.schemaname, +a.tablename , +d.description, +'TABLE' +from sys_tables a +inner join sys_namespace b on b.nspname = a.schemaname +inner join sys_class c on c.relnamespace = b.oid and c.relname = a.tablename +left join sys_description d on d.objoid = c.oid and objsubid = 0 +where a.schemaname not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') +and b.nspname || '.' || a.tablename not in ('PUBLIC.SPATIAL_REF_SYS') + +union all + +select +b.nspname || '.' || a.relname, +b.nspname, +a.relname, +d.description, +'VIEW' +from sys_class a +inner join sys_namespace b on b.oid = a.relnamespace +left join sys_description d on d.objoid = a.oid and objsubid = 0 +where b.nspname not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') and a.relkind in ('m','v') +and b.nspname || '.' || a.relname not in ('PUBLIC.GEOGRAPHY_COLUMNS','PUBLIC.GEOMETRY_COLUMNS','PUBLIC.RASTER_COLUMNS','PUBLIC.RASTER_OVERVIEWS') +{(tbname == null ? "" : $") ft_dbf where {(ignoreCase ? "lower(schemaname)" : "schemaname")}={_commonUtils.FormatSql("{0}", tbname[0])} and {(ignoreCase ? "lower(tablename)" : "tablename")}={_commonUtils.FormatSql("{0}", tbname[1])}")}"; + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var loc6 = new List(); + var loc66 = new List(); + var loc6_1000 = new List(); + var loc66_1000 = new List(); + foreach (object[] row in ds) + { + var object_id = string.Concat(row[0]); + var owner = string.Concat(row[1]); + var table = string.Concat(row[2]); + var comment = string.Concat(row[3]); + Enum.TryParse(string.Concat(row[4]), out var type); + loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Comment = comment, Type = type }); + loc3.Add(object_id, new Dictionary()); + switch (type) + { + case DbTableType.VIEW: + case DbTableType.TABLE: + loc6_1000.Add(object_id); + if (loc6_1000.Count >= 500) + { + loc6.Add(loc6_1000.ToArray()); + loc6_1000.Clear(); + } + break; + case DbTableType.StoreProcedure: + loc66_1000.Add(object_id); + if (loc66_1000.Count >= 500) + { + loc66.Add(loc66_1000.ToArray()); + loc66_1000.Clear(); + } + break; + } + } + if (loc6_1000.Count > 0) loc6.Add(loc6_1000.ToArray()); + if (loc66_1000.Count > 0) loc66.Add(loc66_1000.ToArray()); + + if (loc6.Count == 0) return loc1; + var loc8 = new StringBuilder().Append("("); + for (var loc8idx = 0; loc8idx < loc6.Count; loc8idx++) + { + if (loc8idx > 0) loc8.Append(" OR "); + loc8.Append("a.table_name in ("); + for (var loc8idx2 = 0; loc8idx2 < loc6[loc8idx].Length; loc8idx2++) + { + if (loc8idx2 > 0) loc8.Append(","); + loc8.Append($"'{loc6[loc8idx][loc8idx2]}'"); + } + loc8.Append(")"); + } + loc8.Append(")"); + + sql = $@" +select +ns.nspname || '.' || c.relname as id, +a.attname, +t.typname, +case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len, +case when t.typelem = 0 then t.typname else t2.typname end, +case when a.attnotnull then 0 else 1 end as is_nullable, +--e.adsrc as is_identity, pg12以下 +(select sys_get_expr(adbin, adrelid) from sys_attrdef where adrelid = e.adrelid and adnum = e.adnum limit 1) is_identity, +d.description as comment, +a.attndims, +case when t.typelem = 0 then t.typtype else t2.typtype end, +ns2.nspname, +a.attnum +from sys_class c +inner join sys_attribute a on a.attnum > 0 and a.attrelid = c.oid +inner join sys_type t on t.oid = a.atttypid +left join sys_type t2 on t2.oid = t.typelem +left join sys_description d on d.objoid = a.attrelid and d.objsubid = a.attnum +left join sys_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum +inner join sys_namespace ns on ns.oid = c.relnamespace +inner join sys_namespace ns2 on ns2.oid = t.typnamespace +where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || c.relname")}"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var position = 0; + foreach (object[] row in ds) + { + var object_id = string.Concat(row[0]); + var column = string.Concat(row[1]); + var type = string.Concat(row[2]); + var max_length = int.Parse(string.Concat(row[3])); + var sqlType = string.Concat(row[4]); + var is_nullable = string.Concat(row[5]) == "1"; + var is_identity = string.Concat(row[6]).StartsWith(@"NEXTVAL('") && (string.Concat(row[6]).EndsWith(@"'::REGCLASS)") || string.Concat(row[6]).EndsWith(@"')")); + var comment = string.Concat(row[7]); + var defaultValue = string.Concat(row[6]); + int attndims = int.Parse(string.Concat(row[8])); + string typtype = string.Concat(row[9]); + string owner = string.Concat(row[10]); + int attnum = int.Parse(string.Concat(row[11])); + switch (sqlType.ToLower()) + { + case "bool": case "name": case "bit": case "varbit": case "bpchar": case "varchar": case "bytea": case "text": case "uuid": break; + default: max_length *= 8; break; + } + if (max_length <= 0) max_length = -1; + if (type.StartsWith("_")) + { + type = type.Substring(1); + if (attndims == 0) attndims++; + } + if (sqlType.StartsWith("_")) sqlType = sqlType.Substring(1); + if (max_length > 0) + { + switch (sqlType.ToLower()) + { + //case "numeric": sqlType += $"({max_length})"; break; + case "bpchar": case "varchar": case "bytea": case "bit": case "varbit": sqlType += $"({max_length})"; break; + } + } + if (attndims > 0) type += "[]"; + + loc3[object_id].Add(column, new DbColumnInfo + { + Name = column, + MaxLength = max_length, + IsIdentity = is_identity, + IsNullable = is_nullable, + IsPrimary = false, + DbTypeText = type, + DbTypeTextFull = sqlType, + Table = loc2[object_id], + Coment = comment, + DefaultValue = defaultValue, + Position = ++position + }); + loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]); + loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]); + } + + sql = $@" +select +ns.nspname || '.' || d.relname as table_id, +c.attname, +b.relname as index_id, +case when a.indisunique then 1 else 0 end IsUnique, +case when a.indisprimary then 1 else 0 end IsPrimary, +case when a.indisclustered then 0 else 1 end IsClustered, +case when sys_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, +a.indkey::text, +c.attnum +from sys_index a +inner join sys_class b on b.oid = a.indexrelid +inner join sys_attribute c on c.attnum > 0 and c.attrelid = b.oid +inner join sys_namespace ns on ns.oid = b.relnamespace +inner join sys_class d on d.oid = a.indrelid +where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || d.relname")} +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); + foreach (object[] row in ds) + { + var object_id = string.Concat(row[0]); + var column = string.Concat(row[1]); + var index_id = string.Concat(row[2]); + var is_unique = string.Concat(row[3]) == "1"; + var is_primary_key = string.Concat(row[4]) == "1"; + var is_clustered = string.Concat(row[5]) == "1"; + var is_desc = string.Concat(row[6]) == "1"; + var inkey = string.Concat(row[7]).Split(' '); + var attnum = int.Parse(string.Concat(row[8])); + attnum = int.Parse(inkey[attnum - 1]); + foreach (string tc in loc3[object_id].Keys) + { + if (loc3[object_id][tc].DbTypeText.EndsWith("[]")) + { + column = tc; + break; + } + } + if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue; + var loc9 = loc3[object_id][column]; + if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; + + Dictionary loc10 = null; + DbIndexInfo loc11 = null; + if (!indexColumns.TryGetValue(object_id, out loc10)) + indexColumns.Add(object_id, loc10 = new Dictionary()); + if (!loc10.TryGetValue(index_id, out loc11)) + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); + if (is_unique && !is_primary_key) + { + if (!uniqueColumns.TryGetValue(object_id, out loc10)) + uniqueColumns.Add(object_id, loc10 = new Dictionary()); + if (!loc10.TryGetValue(index_id, out loc11)) + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); + } + } + foreach (var object_id in indexColumns.Keys) + { + foreach (var column in indexColumns[object_id]) + loc2[object_id].IndexesDict.Add(column.Key, column.Value); + } + foreach (var object_id in uniqueColumns.Keys) + { + foreach (var column in uniqueColumns[object_id]) + { + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); + loc2[object_id].UniquesDict.Add(column.Key, column.Value); + } + } + + if (tbname == null) + { + sql = $@" +select +ns.nspname || '.' || b.relname as table_id, +array(select attname from sys_attribute where attrelid = a.conrelid and attnum = any(a.conkey)) as column_name, +a.conname as FKId, +ns2.nspname || '.' || c.relname as ref_table_id, +1 as IsForeignKey, +array(select attname from sys_attribute where attrelid = a.confrelid and attnum = any(a.confkey)) as ref_column, +null ref_sln, +null ref_table +from sys_constraint a +inner join sys_class b on b.oid = a.conrelid +inner join sys_class c on c.oid = a.confrelid +inner join sys_namespace ns on ns.oid = b.relnamespace +inner join sys_namespace ns2 on ns2.oid = c.relnamespace +where {loc8.ToString().Replace("a.table_name", "ns.nspname || '.' || b.relname")} +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; + + var fkColumns = new Dictionary>(); + foreach (object[] row in ds) + { + var table_id = string.Concat(row[0]); + var column = row[1] as string[]; + var fk_id = string.Concat(row[2]); + var ref_table_id = string.Concat(row[3]); + var is_foreign_key = string.Concat(row[4]) == "1"; + var referenced_column = row[5] as string[]; + var referenced_db = string.Concat(row[6]); + var referenced_table = string.Concat(row[7]); + + if (loc2.ContainsKey(ref_table_id) == false) continue; + + Dictionary loc12 = null; + DbForeignInfo loc13 = null; + if (!fkColumns.TryGetValue(table_id, out loc12)) + fkColumns.Add(table_id, loc12 = new Dictionary()); + if (!loc12.TryGetValue(fk_id, out loc13)) + loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc2[ref_table_id] }); + + for (int a = 0; a < column.Length; a++) + { + loc13.Columns.Add(loc3[table_id][column[a]]); + loc13.ReferencedColumns.Add(loc3[ref_table_id][referenced_column[a]]); + } + } + foreach (var table_id in fkColumns.Keys) + foreach (var fk in fkColumns[table_id]) + loc2[table_id].ForeignsDict.Add(fk.Key, fk.Value); + } + + foreach (var table_id in loc3.Keys) + { + foreach (var loc5 in loc3[table_id].Values) + { + loc2[table_id].Columns.Add(loc5); + if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5); + if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5); + } + } + foreach (var loc4 in loc2.Values) + { + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} + loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + loc4.Columns.Sort((c1, c2) => + { + int compare = c2.IsPrimary.CompareTo(c1.IsPrimary); + if (compare == 0) + { + bool b1 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c1.Name).Any()).Any(); + bool b2 = loc4.ForeignsDict.Values.Where(fk => fk.Columns.Where(c3 => c3.Name == c2.Name).Any()).Any(); + compare = b2.CompareTo(b1); + } + if (compare == 0) compare = c1.Name.CompareTo(c2.Name); + return compare; + }); + loc1.Add(loc4); + } + loc1.Sort((t1, t2) => + { + var ret = t1.Schema.CompareTo(t2.Schema); + if (ret == 0) ret = t1.Name.CompareTo(t2.Name); + return ret; + }); + + loc2.Clear(); + loc3.Clear(); + tables.AddRange(loc1); + } + return tables; + } + + public class GetEnumsByDatabaseQueryInfo + { + public string name { get; set; } + public string label { get; set; } + } + public List GetEnumsByDatabase(params string[] database) + { + if (database == null || database.Length == 0) return new List(); + var drs = _orm.Ado.Query(CommandType.Text, _commonUtils.FormatSql(@" +select +ns.nspname || '.' || a.typname AS name, +b.enumlabel AS label +from sys_type a +inner join sys_enum b on b.enumtypid = a.oid +inner join sys_namespace ns on ns.oid = a.typnamespace +where a.typtype = 'e' and ns.nspname in (SELECT schema_name FROM information_schema.schemata where catalog_name in {0})", database)); + var ret = new Dictionary>(); + foreach (var dr in drs) + { + if (ret.TryGetValue(dr.name, out var labels) == false) ret.Add(dr.name, labels = new Dictionary()); + var key = dr.label; + if (Regex.IsMatch(key, @"^[\u0391-\uFFE5a-zA-Z_\$][\u0391-\uFFE5a-zA-Z_\$\d]*$") == false) + key = $"Unkown{ret[dr.name].Count + 1}"; + if (labels.ContainsKey(key) == false) labels.Add(key, dr.label); + } + return ret.Select(a => new DbEnumInfo { Name = a.Key, Labels = a.Value }).ToList(); + } + } +} \ No newline at end of file diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESExpression.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESExpression.cs new file mode 100644 index 00000000..13f2b195 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESExpression.cs @@ -0,0 +1,622 @@ +using FreeSql.Internal; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Text.RegularExpressions; + +namespace FreeSql.KingbaseES +{ + class KingbaseESExpression : CommonExpression + { + + public KingbaseESExpression(CommonUtils common) : base(common) { } + + public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc) + { + Func getExp = exparg => ExpressionLambdaToSql(exparg, tsc); + switch (exp.NodeType) + { + case ExpressionType.Convert: + var operandExp = (exp as UnaryExpression)?.Operand; + var gentype = exp.Type.NullableTypeOrThis(); + if (gentype != operandExp.Type.NullableTypeOrThis()) + { + switch (exp.Type.NullableTypeOrThis().ToString()) + { + case "System.Boolean": return $"(({getExp(operandExp)})::varchar not in ('0','false','f','no'))"; + case "System.Byte": return $"({getExp(operandExp)})::int2"; + case "System.Char": return $"substr(({getExp(operandExp)})::char, 1, 1)"; + case "System.DateTime": return $"({getExp(operandExp)})::timestamp"; + case "System.Decimal": return $"({getExp(operandExp)})::numeric"; + case "System.Double": return $"({getExp(operandExp)})::float8"; + case "System.Int16": return $"({getExp(operandExp)})::int2"; + case "System.Int32": return $"({getExp(operandExp)})::int4"; + case "System.Int64": return $"({getExp(operandExp)})::int8"; + case "System.SByte": return $"({getExp(operandExp)})::int2"; + case "System.Single": return $"({getExp(operandExp)})::float4"; + case "System.String": return $"({getExp(operandExp)})::text"; + case "System.UInt16": return $"({getExp(operandExp)})::int2"; + case "System.UInt32": return $"({getExp(operandExp)})::int4"; + case "System.UInt64": return $"({getExp(operandExp)})::int8"; + case "System.Guid": return $"({getExp(operandExp)})::uuid"; + } + } + break; + case ExpressionType.ArrayLength: + var arrOperExp = getExp((exp as UnaryExpression).Operand); + if (arrOperExp.StartsWith("(") || arrOperExp.EndsWith(")")) return $"array_length(array[{arrOperExp.TrimStart('(').TrimEnd(')')}],1)"; + return $"case when {arrOperExp} is null then 0 else array_length({arrOperExp},1) end"; + case ExpressionType.Call: + var callExp = exp as MethodCallExpression; + + switch (callExp.Method.Name) + { + case "Parse": + case "TryParse": + switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString()) + { + case "System.Boolean": return $"(({getExp(callExp.Arguments[0])})::varchar not in ('0','false','f','no'))"; + case "System.Byte": return $"({getExp(callExp.Arguments[0])})::int2"; + case "System.Char": return $"substr(({getExp(callExp.Arguments[0])})::char, 1, 1)"; + case "System.DateTime": return $"({getExp(callExp.Arguments[0])})::timestamp"; + case "System.Decimal": return $"({getExp(callExp.Arguments[0])})::numeric"; + case "System.Double": return $"({getExp(callExp.Arguments[0])})::float8"; + case "System.Int16": return $"({getExp(callExp.Arguments[0])})::int2"; + case "System.Int32": return $"({getExp(callExp.Arguments[0])})::int4"; + case "System.Int64": return $"({getExp(callExp.Arguments[0])})::int8"; + case "System.SByte": return $"({getExp(callExp.Arguments[0])})::int2"; + case "System.Single": return $"({getExp(callExp.Arguments[0])})::float4"; + case "System.UInt16": return $"({getExp(callExp.Arguments[0])})::int2"; + case "System.UInt32": return $"({getExp(callExp.Arguments[0])})::int4"; + case "System.UInt64": return $"({getExp(callExp.Arguments[0])})::int8"; + case "System.Guid": return $"({getExp(callExp.Arguments[0])})::uuid"; + } + break; + case "NewGuid": + return null; + case "Next": + if (callExp.Object?.Type == typeof(Random)) return "(random()*1000000000)::int4"; + return null; + case "NextDouble": + if (callExp.Object?.Type == typeof(Random)) return "random()"; + return null; + case "Random": + if (callExp.Method.DeclaringType.IsNumberType()) return "random()"; + return null; + case "ToString": + if (callExp.Object != null) return callExp.Arguments.Count == 0 ? $"({getExp(callExp.Object)})::text" : null; + return null; + } + + var objExp = callExp.Object; + var objType = objExp?.Type; + if (objType?.FullName == "System.Byte[]") return null; + + var argIndex = 0; + if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable)) + { + objExp = callExp.Arguments.FirstOrDefault(); + objType = objExp?.Type; + argIndex++; + + if (objType == typeof(string)) + { + switch (callExp.Method.Name) + { + case "First": + case "FirstOrDefault": + return $"substr({getExp(callExp.Arguments[0])}, 1, 1)"; + } + } + } + if (objType == null) objType = callExp.Method.DeclaringType; + if (objType != null || objType.IsArrayOrList()) + { + string left = null; + if (objType.FullName == typeof(Dictionary).FullName) + { + left = objExp == null ? null : getExp(objExp); + switch (callExp.Method.Name) + { + case "Contains": + var right = getExp(callExp.Arguments[argIndex]); + return $"({left} @> ({right}))"; + case "ContainsKey": return $"({left} ? {getExp(callExp.Arguments[argIndex])})"; + case "Concat": return $"({left} || {getExp(callExp.Arguments[argIndex])})"; + case "GetLength": + case "GetLongLength": + case "Count": return $"case when {left} is null then 0 else array_length(akeys({left}),1) end"; + case "Keys": return $"akeys({left})"; + case "Values": return $"avals({left})"; + } + } + switch (callExp.Method.Name) + { + case "Any": + left = objExp == null ? null : getExp(objExp); + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + return $"(case when {left} is null then 0 else array_length({left},1) end > 0)"; + case "Contains": + tsc.SetMapColumnTmp(null); + var args1 = getExp(callExp.Arguments[argIndex]); + var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp); + var oldDbParams = tsc.SetDbParamsReturnOld(null); + left = objExp == null ? null : getExp(objExp); + tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType); + tsc.SetDbParamsReturnOld(oldDbParams); + //判断 in 或 array @> array + if (left.StartsWith("array[") || left.EndsWith("]")) + return $"({args1}) in ({left.Substring(6, left.Length - 7)})"; + if (left.StartsWith("(") || left.EndsWith(")")) //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格 + return $"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})"; + if (args1.StartsWith("(") || args1.EndsWith(")")) args1 = $"array[{args1.TrimStart('(').TrimEnd(')')}]"; + args1 = $"array[{args1}]"; + if (objExp != null) + { + var dbinfo = _common._orm.CodeFirst.GetDbInfo(objExp.Type); + if (dbinfo != null) args1 = $"{args1}::{dbinfo.dbtype}"; + } + return $"({left} @> {args1})"; + case "Concat": + left = objExp == null ? null : getExp(objExp); + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + var right2 = getExp(callExp.Arguments[argIndex]); + if (right2.StartsWith("(") || right2.EndsWith(")")) right2 = $"array[{right2.TrimStart('(').TrimEnd(')')}]"; + return $"({left} || {right2})"; + case "GetLength": + case "GetLongLength": + case "Length": + case "Count": + left = objExp == null ? null : getExp(objExp); + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + return $"case when {left} is null then 0 else array_length({left},1) end"; + } + } + break; + case ExpressionType.MemberAccess: + var memExp = exp as MemberExpression; + var memParentExp = memExp.Expression?.Type; + if (memParentExp?.FullName == "System.Byte[]") return null; + if (memParentExp != null) + { + if (memParentExp.IsArray == true) + { + var left = getExp(memExp.Expression); + if (left.StartsWith("(") || left.EndsWith(")")) left = $"array[{left.TrimStart('(').TrimEnd(')')}]"; + switch (memExp.Member.Name) + { + case "Length": + case "Count": return $"case when {left} is null then 0 else array_length({left},1) end"; + } + } + } + break; + case ExpressionType.NewArrayInit: + var arrExp = exp as NewArrayExpression; + var arrSb = new StringBuilder(); + arrSb.Append("array["); + for (var a = 0; a < arrExp.Expressions.Count; a++) + { + if (a > 0) arrSb.Append(","); + arrSb.Append(getExp(arrExp.Expressions[a])); + } + if (arrSb.Length == 1) arrSb.Append("NULL"); + return arrSb.Append("]").ToString(); + case ExpressionType.ListInit: + var listExp = exp as ListInitExpression; + var listSb = new StringBuilder(); + listSb.Append("("); + for (var a = 0; a < listExp.Initializers.Count; a++) + { + if (listExp.Initializers[a].Arguments.Any() == false) continue; + if (a > 0) listSb.Append(","); + listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault())); + } + if (listSb.Length == 1) listSb.Append("NULL"); + return listSb.Append(")").ToString(); + case ExpressionType.New: + var newExp = exp as NewExpression; + if (typeof(IList).IsAssignableFrom(newExp.Type)) + { + if (newExp.Arguments.Count == 0) return "(NULL)"; + if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) return "(NULL)"; + return getExp(newExp.Arguments[0]); + } + return null; + } + return null; + } + + public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc) + { + if (exp.Expression == null) + { + switch (exp.Member.Name) + { + case "Empty": return "''"; + } + return null; + } + var left = ExpressionLambdaToSql(exp.Expression, tsc); + switch (exp.Member.Name) + { + case "Length": return $"char_length({left})"; + } + return null; + } + public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc) + { + if (exp.Expression == null) + { + switch (exp.Member.Name) + { + case "Now": return _common.Now; + case "UtcNow": return _common.NowUtc; + case "Today": return "current_date"; + case "MinValue": return "'0001/1/1 0:00:00'::timestamp"; + case "MaxValue": return "'9999/12/31 23:59:59'::timestamp"; + } + return null; + } + var left = ExpressionLambdaToSql(exp.Expression, tsc); + switch (exp.Member.Name) + { + case "Date": return $"({left})::date"; + case "TimeOfDay": return $"(extract(epoch from ({left})::time)*1000000)"; + case "DayOfWeek": return $"extract(dow from ({left})::timestamp)"; + case "Day": return $"extract(day from ({left})::timestamp)"; + case "DayOfYear": return $"extract(doy from ({left})::timestamp)"; + case "Month": return $"extract(month from ({left})::timestamp)"; + case "Year": return $"extract(year from ({left})::timestamp)"; + case "Hour": return $"extract(hour from ({left})::timestamp)"; + case "Minute": return $"extract(minute from ({left})::timestamp)"; + case "Second": return $"extract(second from ({left})::timestamp)"; + case "Millisecond": return $"(extract(milliseconds from ({left})::timestamp)-extract(second from ({left})::timestamp)*1000)"; + case "Ticks": return $"(extract(epoch from ({left})::timestamp)*10000000+621355968000000000)"; + } + return null; + } + public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc) + { + if (exp.Expression == null) + { + switch (exp.Member.Name) + { + case "Zero": return "0"; + case "MinValue": return "-922337203685477580"; //微秒 Ticks / 10 + case "MaxValue": return "922337203685477580"; + } + return null; + } + var left = ExpressionLambdaToSql(exp.Expression, tsc); + switch (exp.Member.Name) + { + case "Days": return $"floor(({left})/{(long)1000000 * 60 * 60 * 24})"; + case "Hours": return $"floor(({left})/{(long)1000000 * 60 * 60}%24)"; + case "Milliseconds": return $"(floor(({left})/1000)::int8%1000)"; + case "Minutes": return $"(floor(({left})/{(long)1000000 * 60})::int8%60)"; + case "Seconds": return $"(floor(({left})/1000000)::int8%60)"; + case "Ticks": return $"(({left})*10)"; + case "TotalDays": return $"(({left})/{(long)1000000 * 60 * 60 * 24})"; + case "TotalHours": return $"(({left})/{(long)1000000 * 60 * 60})"; + case "TotalMilliseconds": return $"(({left})/1000)"; + case "TotalMinutes": return $"(({left})/{(long)1000000 * 60})"; + case "TotalSeconds": return $"(({left})/1000000)"; + } + return null; + } + + public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc) + { + Func getExp = exparg => ExpressionLambdaToSql(exparg, tsc); + if (exp.Object == null) + { + switch (exp.Method.Name) + { + case "IsNullOrEmpty": + var arg1 = getExp(exp.Arguments[0]); + return $"({arg1} is null or {arg1} = '')"; + case "IsNullOrWhiteSpace": + var arg2 = getExp(exp.Arguments[0]); + return $"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')"; + case "Concat": + return _common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null); + case "Format": + if (exp.Arguments[0].NodeType != ExpressionType.Constant) throw new Exception($"未实现函数表达式 {exp} 解析,参数 {exp.Arguments[0]} 必须为常量"); + var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ? + (exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0); + //3个 {} 时,Arguments 解析出来是分开的 + //4个 {} 时,Arguments[1] 只能解析这个出来,然后里面是 NewArray [] + var expArgs = expArgsHack.Select(a => + { + var atype = (a as UnaryExpression)?.Operand.Type.NullableTypeOrThis() ?? a.Type.NullableTypeOrThis(); + if (atype == typeof(string)) return $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'"; + return $"'||{_common.IsNull($"({ExpressionLambdaToSql(a, tsc)})::text", "''")}||'"; + }).ToArray(); + return string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs); + case "Join": + if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1)) + { + var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod, + Expression.Lambda( + Expression.Call( + typeof(SqlExtExtensions).GetMethod("StringJoinPgsqlGroupConcat"), + Expression.Convert(toListArgs1.Body, typeof(object)), + Expression.Convert(exp.Arguments[0], typeof(object))), + toListArgs1.Parameters)); + var newToListSql = getExp(newToListArgs0); + return newToListSql; + } + break; + } + } + else + { + var left = getExp(exp.Object); + switch (exp.Method.Name) + { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = getExp(exp.Arguments[0]); + if (args0Value == "NULL") return $"({left}) IS NULL"; + var likeOpt = "LIKE"; + if (exp.Arguments.Count > 1) + { + if (exp.Arguments[1].Type == typeof(bool) || + exp.Arguments[1].Type == typeof(StringComparison)) likeOpt = "ILIKE"; + } + if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::text || '%')")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::text)")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) {likeOpt} ('%' || ({args0Value})::text || '%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = getExp(exp.Arguments[0]); + if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); + else substrArgs1 += "+1"; + if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; + return $"substr({left}, {substrArgs1}, {getExp(exp.Arguments[1])})"; + case "IndexOf": return $"(strpos({left}, {getExp(exp.Arguments[0])})-1)"; + case "PadLeft": + if (exp.Arguments.Count == 1) return $"lpad({left}, {getExp(exp.Arguments[0])})"; + return $"lpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; + case "PadRight": + if (exp.Arguments.Count == 1) return $"rpad({left}, {getExp(exp.Arguments[0])})"; + return $"rpad({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; + case "Trim": + case "TrimStart": + case "TrimEnd": + if (exp.Arguments.Count == 0) + { + if (exp.Method.Name == "Trim") return $"trim({left})"; + if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; + if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; + } + foreach (var argsTrim02 in exp.Arguments) + { + var argsTrim01s = new[] { argsTrim02 }; + if (argsTrim02.NodeType == ExpressionType.NewArrayInit) + { + var arritem = argsTrim02 as NewArrayExpression; + argsTrim01s = arritem.Expressions.ToArray(); + } + foreach (var argsTrim01 in argsTrim01s) + { + if (exp.Method.Name == "Trim") left = $"trim(both {getExp(argsTrim01)} from {left})"; + if (exp.Method.Name == "TrimStart") left = $"ltrim({left},{getExp(argsTrim01)})"; + if (exp.Method.Name == "TrimEnd") left = $"rtrim({left},{getExp(argsTrim01)})"; + } + } + return left; + case "Replace": return $"replace({left}, {getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; + case "CompareTo": return $"case when {left} = {getExp(exp.Arguments[0])} then 0 when {left} > {getExp(exp.Arguments[0])} then 1 else -1 end"; + case "Equals": return $"({left} = ({getExp(exp.Arguments[0])})::text)"; + } + } + return null; + } + public override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, ExpTSC tsc) + { + Func getExp = exparg => ExpressionLambdaToSql(exparg, tsc); + switch (exp.Method.Name) + { + case "Abs": return $"abs({getExp(exp.Arguments[0])})"; + case "Sign": return $"sign({getExp(exp.Arguments[0])})"; + case "Floor": return $"floor({getExp(exp.Arguments[0])})"; + case "Ceiling": return $"ceiling({getExp(exp.Arguments[0])})"; + case "Round": + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; + return $"round({getExp(exp.Arguments[0])})"; + case "Exp": return $"exp({getExp(exp.Arguments[0])})"; + case "Log": + if (exp.Arguments.Count > 1) return $"log({getExp(exp.Arguments[1])},{getExp(exp.Arguments[0])})"; + return $"log(2.7182818284590451,{getExp(exp.Arguments[0])})"; + case "Log10": return $"log({getExp(exp.Arguments[0])})"; + case "Pow": return $"pow({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; + case "Sqrt": return $"sqrt({getExp(exp.Arguments[0])})"; + case "Cos": return $"cos({getExp(exp.Arguments[0])})"; + case "Sin": return $"sin({getExp(exp.Arguments[0])})"; + case "Tan": return $"tan({getExp(exp.Arguments[0])})"; + case "Acos": return $"acos({getExp(exp.Arguments[0])})"; + case "Asin": return $"asin({getExp(exp.Arguments[0])})"; + case "Atan": return $"atan({getExp(exp.Arguments[0])})"; + case "Atan2": return $"atan2({getExp(exp.Arguments[0])}, {getExp(exp.Arguments[1])})"; + case "Truncate": return $"trunc({getExp(exp.Arguments[0])}, 0)"; + } + return null; + } + public override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, ExpTSC tsc) + { + Func getExp = exparg => ExpressionLambdaToSql(exparg, tsc); + if (exp.Object == null) + { + switch (exp.Method.Name) + { + case "Compare": return $"extract(epoch from ({getExp(exp.Arguments[0])})::timestamp-({getExp(exp.Arguments[1])})::timestamp)"; + case "DaysInMonth": return $"extract(day from ({getExp(exp.Arguments[0])} || '-' || {getExp(exp.Arguments[1])} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)"; + case "Equals": return $"(({getExp(exp.Arguments[0])})::timestamp = ({getExp(exp.Arguments[1])})::timestamp)"; + + case "IsLeapYear": + var isLeapYearArgs1 = getExp(exp.Arguments[0]); + return $"(({isLeapYearArgs1})::int8%4=0 AND ({isLeapYearArgs1})::int8%100<>0 OR ({isLeapYearArgs1})::int8%400=0)"; + + case "Parse": return $"({getExp(exp.Arguments[0])})::timestamp"; + case "ParseExact": + case "TryParse": + case "TryParseExact": return $"({getExp(exp.Arguments[0])})::timestamp"; + } + } + else + { + var left = getExp(exp.Object); + var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]); + switch (exp.Method.Name) + { + case "Add": return $"(({left})::timestamp+((({args1})/1000)||' milliseconds')::interval)"; + case "AddDays": return $"(({left})::timestamp+(({args1})||' day')::interval)"; + case "AddHours": return $"(({left})::timestamp+(({args1})||' hour')::interval)"; + case "AddMilliseconds": return $"(({left})::timestamp+(({args1})||' milliseconds')::interval)"; + case "AddMinutes": return $"(({left})::timestamp+(({args1})||' minute')::interval)"; + case "AddMonths": return $"(({left})::timestamp+(({args1})||' month')::interval)"; + case "AddSeconds": return $"(({left})::timestamp+(({args1})||' second')::interval)"; + case "AddTicks": return $"(({left})::timestamp+(({args1})/10||' microseconds')::interval)"; + case "AddYears": return $"(({left})::timestamp+(({args1})||' year')::interval)"; + case "Subtract": + switch ((exp.Arguments[0].Type.IsNullableType() ? exp.Arguments[0].Type.GetGenericArguments().FirstOrDefault() : exp.Arguments[0].Type).FullName) + { + case "System.DateTime": return $"(extract(epoch from ({left})::timestamp-({args1})::timestamp)*1000000)"; + case "System.TimeSpan": return $"(({left})::timestamp-((({args1})/1000)||' milliseconds')::interval)"; + } + break; + case "Equals": return $"({left} = ({args1})::timestamp)"; + case "CompareTo": return $"extract(epoch from ({left})::timestamp-({args1})::timestamp)"; + case "ToString": + if (left.EndsWith("::timestamp") == false) left = $"({left})::timestamp"; + if (exp.Arguments.Count == 0) return $"to_char({left},'YYYY-MM-DD HH24:MI:SS.US')"; + switch (args1) + { + case "'yyyy-MM-dd HH:mm:ss'": return $"to_char({left},'YYYY-MM-DD HH24:MI:SS')"; + case "'yyyy-MM-dd HH:mm'": return $"to_char({left},'YYYY-MM-DD HH24:MI')"; + case "'yyyy-MM-dd HH'": return $"to_char({left},'YYYY-MM-DD HH24')"; + case "'yyyy-MM-dd'": return $"to_char({left},'YYYY-MM-DD')"; + case "'yyyy-MM'": return $"to_char({left},'YYYY-MM')"; + case "'yyyyMMddHHmmss'": return $"to_char({left},'YYYYMMDDHH24MISS')"; + case "'yyyyMMddHHmm'": return $"to_char({left},'YYYYMMDDHH24MI')"; + case "'yyyyMMddHH'": return $"to_char({left},'YYYYMMDDHH24')"; + case "'yyyyMMdd'": return $"to_char({left},'YYYYMMDD')"; + case "'yyyyMM'": return $"to_char({left},'YYYYMM')"; + case "'yyyy'": return $"to_char({left},'YYYY')"; + case "'HH:mm:ss'": return $"to_char({left},'HH24:MI:SS')"; + } + args1 = Regex.Replace(args1, "(yyyy|yy|MM|dd|HH|hh|mm|ss|tt)", m => + { + switch (m.Groups[1].Value) + { + case "yyyy": return $"YYYY"; + case "yy": return $"YY"; + case "MM": return $"%_a1"; + case "dd": return $"%_a2"; + case "HH": return $"%_a3"; + case "hh": return $"%_a4"; + case "mm": return $"%_a5"; + case "ss": return $"SS"; + case "tt": return $"%_a6"; + } + return m.Groups[0].Value; + }); + var argsFinds = new[] { "YYYY", "YY", "%_a1", "%_a2", "%_a3", "%_a4", "%_a5", "SS", "%_a6" }; + var argsSpts = Regex.Split(args1, "(M|d|H|h|m|s|t)"); + for (var a = 0; a < argsSpts.Length; a++) + { + switch (argsSpts[a]) + { + case "M": argsSpts[a] = $"ltrim(to_char({left},'MM'),'0')"; break; + case "d": argsSpts[a] = $"case when substr(to_char({left},'DD'),1,1) = '0' then substr(to_char({left},'DD'),2,1) else to_char({left},'DD') end"; break; + case "H": argsSpts[a] = $"case when substr(to_char({left},'HH24'),1,1) = '0' then substr(to_char({left},'HH24'),2,1) else to_char({left},'HH24') end"; break; + case "h": argsSpts[a] = $"case when substr(to_char({left},'HH12'),1,1) = '0' then substr(to_char({left},'HH12'),2,1) else to_char({left},'HH12') end"; break; + case "m": argsSpts[a] = $"case when substr(to_char({left},'MI'),1,1) = '0' then substr(to_char({left},'MI'),2,1) else to_char({left},'MI') end"; break; + case "s": argsSpts[a] = $"case when substr(to_char({left},'SS'),1,1) = '0' then substr(to_char({left},'SS'),2,1) else to_char({left},'SS') end"; break; + case "t": argsSpts[a] = $"rtrim(to_char({left},'AM'),'M')"; break; + default: + var argsSptsA = argsSpts[a]; + if (argsSptsA.StartsWith("'")) argsSptsA = argsSptsA.Substring(1); + if (argsSptsA.EndsWith("'")) argsSptsA = argsSptsA.Remove(argsSptsA.Length - 1); + argsSpts[a] = argsFinds.Any(m => argsSptsA.Contains(m)) ? $"to_char({left},'{argsSptsA}')" : $"'{argsSptsA}'"; + break; + } + } + if (argsSpts.Length > 0) args1 = $"({string.Join(" || ", argsSpts.Where(a => a != "''"))})"; + return args1.Replace("%_a1", "MM").Replace("%_a2", "DD").Replace("%_a3", "HH24").Replace("%_a4", "HH12").Replace("%_a5", "MI").Replace("%_a6", "AM"); + } + } + return null; + } + public override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, ExpTSC tsc) + { + Func getExp = exparg => ExpressionLambdaToSql(exparg, tsc); + if (exp.Object == null) + { + switch (exp.Method.Name) + { + case "Compare": return $"({getExp(exp.Arguments[0])}-({getExp(exp.Arguments[1])}))"; + case "Equals": return $"({getExp(exp.Arguments[0])} = {getExp(exp.Arguments[1])})"; + case "FromDays": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60 * 24})"; + case "FromHours": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60 * 60})"; + case "FromMilliseconds": return $"(({getExp(exp.Arguments[0])})*1000)"; + case "FromMinutes": return $"(({getExp(exp.Arguments[0])})*{(long)1000000 * 60})"; + case "FromSeconds": return $"(({getExp(exp.Arguments[0])})*1000000)"; + case "FromTicks": return $"(({getExp(exp.Arguments[0])})/10)"; + case "Parse": return $"({getExp(exp.Arguments[0])})::int8"; + case "ParseExact": + case "TryParse": + case "TryParseExact": return $"({getExp(exp.Arguments[0])})::int8"; + } + } + else + { + var left = getExp(exp.Object); + var args1 = exp.Arguments.Count == 0 ? null : getExp(exp.Arguments[0]); + switch (exp.Method.Name) + { + case "Add": return $"({left}+{args1})"; + case "Subtract": return $"({left}-({args1}))"; + case "Equals": return $"({left} = {args1})"; + case "CompareTo": return $"({left}-({args1}))"; + case "ToString": return $"({left})::varchar"; + } + } + return null; + } + public override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, ExpTSC tsc) + { + Func getExp = exparg => ExpressionLambdaToSql(exparg, tsc); + if (exp.Object == null) + { + switch (exp.Method.Name) + { + case "ToBoolean": return $"(({getExp(exp.Arguments[0])})::varchar not in ('0','false','f','no'))"; + case "ToByte": return $"({getExp(exp.Arguments[0])})::int2"; + case "ToChar": return $"substr(({getExp(exp.Arguments[0])})::char, 1, 1)"; + case "ToDateTime": return $"({getExp(exp.Arguments[0])})::timestamp"; + case "ToDecimal": return $"({getExp(exp.Arguments[0])})::numeric"; + case "ToDouble": return $"({getExp(exp.Arguments[0])})::float8"; + case "ToInt16": return $"({getExp(exp.Arguments[0])})::int2"; + case "ToInt32": return $"({getExp(exp.Arguments[0])})::int4"; + case "ToInt64": return $"({getExp(exp.Arguments[0])})::int8"; + case "ToSByte": return $"({getExp(exp.Arguments[0])})::int2"; + case "ToSingle": return $"({getExp(exp.Arguments[0])})::float4"; + case "ToString": return $"({getExp(exp.Arguments[0])})::text"; + case "ToUInt16": return $"({getExp(exp.Arguments[0])})::int2"; + case "ToUInt32": return $"({getExp(exp.Arguments[0])})::int4"; + case "ToUInt64": return $"({getExp(exp.Arguments[0])})::int8"; + } + } + return null; + } + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESExtensions.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESExtensions.cs new file mode 100644 index 00000000..be34f19b --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESExtensions.cs @@ -0,0 +1,12 @@ +public static partial class FreeSqlKingbaseESGlobalExtensions +{ + + /// + /// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换 + /// + /// + /// + /// + public static string FormatKingbaseES(this string that, params object[] args) => _kingbaseesAdo.Addslashes(that, args); + static FreeSql.KingbaseES.KingbaseESAdo _kingbaseesAdo = new FreeSql.KingbaseES.KingbaseESAdo(); +} diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESProvider.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESProvider.cs new file mode 100644 index 00000000..c91f9507 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESProvider.cs @@ -0,0 +1,60 @@ +using FreeSql.Internal; +using FreeSql.Internal.CommonProvider; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Threading; + +namespace FreeSql.KingbaseES +{ + + public class KingbaseESProvider : IFreeSql + { + + public ISelect Select() where T1 : class => new KingbaseESSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, null); + public ISelect Select(object dywhere) where T1 : class => new KingbaseESSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); + public IInsert Insert() where T1 : class => new KingbaseESInsert(this, this.InternalCommonUtils, this.InternalCommonExpression); + public IInsert Insert(T1 source) where T1 : class => this.Insert().AppendData(source); + public IInsert Insert(T1[] source) where T1 : class => this.Insert().AppendData(source); + public IInsert Insert(List source) where T1 : class => this.Insert().AppendData(source); + public IInsert Insert(IEnumerable source) where T1 : class => this.Insert().AppendData(source); + public IUpdate Update() where T1 : class => new KingbaseESUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression, null); + public IUpdate Update(object dywhere) where T1 : class => new KingbaseESUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); + public IDelete Delete() where T1 : class => new KingbaseESDelete(this, this.InternalCommonUtils, this.InternalCommonExpression, null); + public IDelete Delete(object dywhere) where T1 : class => new KingbaseESDelete(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); + public IInsertOrUpdate InsertOrUpdate() where T1 : class => new KingbaseESInsertOrUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression); + + public IAdo Ado { get; } + public IAop Aop { get; } + public ICodeFirst CodeFirst { get; } + public IDbFirst DbFirst { get; } + public KingbaseESProvider(string masterConnectionString, string[] slaveConnectionString, Func connectionFactory = null) + { + this.InternalCommonUtils = new KingbaseESUtils(this); + this.InternalCommonExpression = new KingbaseESExpression(this.InternalCommonUtils); + + this.Ado = new KingbaseESAdo(this.InternalCommonUtils, masterConnectionString, slaveConnectionString, connectionFactory); + this.Aop = new AopProvider(); + + this.DbFirst = new KingbaseESDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + this.CodeFirst = new KingbaseESCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression); + } + + internal CommonUtils InternalCommonUtils { get; } + internal CommonExpression InternalCommonExpression { get; } + + public void Transaction(Action handler) => Ado.Transaction(handler); + public void Transaction(IsolationLevel isolationLevel, Action handler) => Ado.Transaction(isolationLevel, handler); + + public GlobalFilter GlobalFilter { get; } = new GlobalFilter(); + + ~KingbaseESProvider() => this.Dispose(); + int _disposeCounter; + public void Dispose() + { + if (Interlocked.Increment(ref _disposeCounter) != 1) return; + (this.Ado as AdoProvider)?.Dispose(); + } + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/KingbaseESUtils.cs b/Providers/FreeSql.Provider.KingbaseES/KingbaseESUtils.cs new file mode 100644 index 00000000..91bc9f92 --- /dev/null +++ b/Providers/FreeSql.Provider.KingbaseES/KingbaseESUtils.cs @@ -0,0 +1,163 @@ +using FreeSql.Internal; +using FreeSql.Internal.Model; +using Kdbndp; +using KdbndpTypes; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace FreeSql.KingbaseES +{ + + class KingbaseESUtils : CommonUtils + { + public KingbaseESUtils(IFreeSql orm) : base(orm) + { + } + + static Array getParamterArrayValue(Type arrayType, object value, object defaultValue) + { + var valueArr = value as Array; + var len = valueArr.GetLength(0); + var ret = Array.CreateInstance(arrayType, len); + for (var a = 0; a < len; a++) + { + var item = valueArr.GetValue(a); + ret.SetValue(item == null ? defaultValue : getParamterValue(item.GetType(), item, 1), a); + } + return ret; + } + static Dictionary> dicGetParamterValue = new Dictionary> { + { typeof(uint).FullName, a => long.Parse(string.Concat(a)) }, { typeof(uint[]).FullName, a => getParamterArrayValue(typeof(long), a, 0) }, { typeof(uint?[]).FullName, a => getParamterArrayValue(typeof(long?), a, null) }, + { typeof(ulong).FullName, a => decimal.Parse(string.Concat(a)) }, { typeof(ulong[]).FullName, a => getParamterArrayValue(typeof(decimal), a, 0) }, { typeof(ulong?[]).FullName, a => getParamterArrayValue(typeof(decimal?), a, null) }, + { typeof(ushort).FullName, a => int.Parse(string.Concat(a)) }, { typeof(ushort[]).FullName, a => getParamterArrayValue(typeof(int), a, 0) }, { typeof(ushort?[]).FullName, a => getParamterArrayValue(typeof(int?), a, null) }, + { typeof(byte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(byte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(byte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) }, + { typeof(sbyte).FullName, a => short.Parse(string.Concat(a)) }, { typeof(sbyte[]).FullName, a => getParamterArrayValue(typeof(short), a, 0) }, { typeof(sbyte?[]).FullName, a => getParamterArrayValue(typeof(short?), a, null) }, + { typeof(char).FullName, a => string.Concat(a).Replace('\0', ' ').ToCharArray().FirstOrDefault() }, + }; + static object getParamterValue(Type type, object value, int level = 0) + { + if (type.FullName == "System.Byte[]") return value; + if (type.IsArray && level == 0) + { + var elementType = type.GetElementType(); + Type enumType = null; + if (elementType.IsEnum) enumType = elementType; + else if (elementType.IsNullableType()) + { + var genericTypesFirst = elementType.GetGenericArguments().First(); + if (genericTypesFirst.IsEnum) enumType = genericTypesFirst; + } + if (enumType != null) return enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ? + getParamterArrayValue(typeof(long), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue()) : + getParamterArrayValue(typeof(int), value, elementType.IsEnum ? null : enumType.CreateInstanceGetDefaultValue()); + return dicGetParamterValue.TryGetValue(type.FullName, out var trydicarr) ? trydicarr(value) : value; + } + if (type.IsNullableType()) type = type.GetGenericArguments().First(); + if (type.IsEnum) return (int)value; + if (dicGetParamterValue.TryGetValue(type.FullName, out var trydic)) return trydic(value); + return value; + } + + public override DbParameter AppendParamter(List _params, string parameterName, ColumnInfo col, Type type, object value) + { + if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; + if (value != null) value = getParamterValue(type, value); + var ret = new KdbndpParameter { ParameterName = QuoteParamterName(parameterName), Value = value }; + //if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) { + // ret.DataTypeName = ""; + //} else { + var tp = _orm.CodeFirst.GetDbInfo(type)?.type; + if (tp != null) ret.KdbndpDbType = (KdbndpDbType)tp.Value; + //} + _params?.Add(ret); + return ret; + } + + public override DbParameter[] GetDbParamtersByObject(string sql, object obj) => + Utils.GetDbParamtersByObject(sql, obj, null, (name, type, value) => + { + if (value != null) value = getParamterValue(type, value); + var ret = new KdbndpParameter { ParameterName = $"@{name.ToUpper()}", Value = value }; + //if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) { + // ret.DataTypeName = ""; + //} else { + var tp = _orm.CodeFirst.GetDbInfo(type)?.type; + if (tp != null) ret.KdbndpDbType = (KdbndpDbType)tp.Value; + //} + return ret; + }); + + public override string FormatSql(string sql, params object[] args) => sql?.FormatKingbaseES(args); + public override string QuoteSqlName(params string[] name) + { + if (name.Length == 1) + { + var nametrim = name[0].Trim(); + if (nametrim.StartsWith("(") && nametrim.EndsWith(")")) + return nametrim; //原生SQL + if (nametrim.StartsWith("\"") && nametrim.EndsWith("\"")) + return nametrim; + return $"\"{nametrim.Replace(".", "\".\"")}\""; + } + return $"\"{string.Join("\".\"", name)}\""; + } + public override string TrimQuoteSqlName(string name) + { + var nametrim = name.Trim(); + if (nametrim.StartsWith("(") && nametrim.EndsWith(")")) + return nametrim; //原生SQL + return $"{nametrim.Trim('"').Replace("\".\"", ".").Replace(".\"", ".")}"; + } + public override string[] SplitTableName(string name) => GetSplitTableNames(name, '"', '"', 2); + public override string QuoteParamterName(string name) => $"@{name.ToUpper()}"; + public override string IsNull(string sql, object value) => $"coalesce({sql}, {value})"; + public override string StringConcat(string[] objs, Type[] types) => $"{string.Join(" || ", objs.Select((a, b) => b == 0 ? $"{a}::text" : a))}"; //First ::text + public override string Mod(string left, string right, Type leftType, Type rightType) => $"{left} % {right}"; + public override string Div(string left, string right, Type leftType, Type rightType) => $"{left} / {right}"; + public override string Now => "current_timestamp"; + public override string NowUtc => "(current_timestamp at time zone 'UTC')"; + + public override string QuoteWriteParamter(Type type, string paramterName) => paramterName; + public override string QuoteReadColumn(Type type, Type mapType, string columnName) => columnName; + + public override string GetNoneParamaterSqlValue(List specialParams, string specialParamFlag, Type type, object value) + { + if (value == null) return "NULL"; + if (type.IsNumberType()) return string.Format(CultureInfo.InvariantCulture, "{0}", value); + value = getParamterValue(type, value); + var type2 = value.GetType(); + if (type2 == typeof(byte[])) return $"'\\x{CommonUtils.BytesSqlRaw(value as byte[])}'"; + if (type2 == typeof(TimeSpan) || type2 == typeof(TimeSpan?)) + { + var ts = (TimeSpan)value; + return $"'{Math.Min(24, (int)Math.Floor(ts.TotalHours))}:{ts.Minutes}:{ts.Seconds}'"; + } + else if (value is Array) + { + var valueArr = value as Array; + var eleType = type2.GetElementType(); + var len = valueArr.GetLength(0); + var sb = new StringBuilder().Append("ARRAY["); + for (var a = 0; a < len; a++) + { + var item = valueArr.GetValue(a); + if (a > 0) sb.Append(","); + sb.Append(GetNoneParamaterSqlValue(specialParams, specialParamFlag, eleType, item)); + } + sb.Append("]"); + var dbinfo = _orm.CodeFirst.GetDbInfo(type); + if (dbinfo != null) sb.Append("::").Append(dbinfo.dbtype); + return sb.ToString(); + } + else if (dicGetParamterValue.ContainsKey(type2.FullName)) + { + value = string.Concat(value); + } + return FormatSql("{0}", value, 1); + } + } +} diff --git a/Providers/FreeSql.Provider.KingbaseES/key.snk b/Providers/FreeSql.Provider.KingbaseES/key.snk new file mode 100644 index 0000000000000000000000000000000000000000..be1149357b2060cb16aa173fa54ed5712e14d886 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098e+`w>!pw~z{kC)(11aic*UA-FJmj*Dw%pGP3~em+rOVqNP@MPQ<0SE0Jw z18wO2D&7?q5r~)y-xHI!=Z`X~3NABfxO*Rt(RKB5xZ1m4DrJj|kVnrZK!68?r~F(^ zF8&@B#vuvJ#~ISY*N$A>FP8GV$Gww<4lAIG`fLSf8o=U$8Q2V1Dw!uRoO@@IXo{{& zGRd>cseR-YBR9`Y3Sh=ZL3z~q?`Grcb>lHDLxwW3}jwu`6-eT*nfH1(XM}Q}C z10NXPe~;ciLC3eO6W_Y0G5RRIAI`cz)T{=Wk%f7<+bDoBRp}Jl!>1+*GaI5un*m5A zkcb_mp6S*!@b5a)>R_yLok1277f`x;0vtz@?PY`FIKqT%3pJ(P8dH+sTWP4`7ovcs zP!O_$q&X`AkNRQULp(?74(v}<+FqM*HT3bo-qLW6n9X*AD6e%;#Z)6<@>~y2hlubU z`Y}D>OQ(AcS4{b1_FAgVBYrD+k!dUgJF0}jGb`A|sl|+^Ai@M&x=dhq`GiOJT&(@p zSnV_FdZQ_y4H|c{MA$s3-uJ>b`BkX%wA!qSd{u8a`l*9Q;gOChlC^WMd@Ts92&B^Q iBbsxrKxd~B8LVo7`w{*T8NJ6Jg9$1yt#;1QpFdUzz91$5 literal 0 HcmV?d00001 diff --git a/Providers/FreeSql.Provider.KingbaseES/lib/Kdbndp.dll b/Providers/FreeSql.Provider.KingbaseES/lib/Kdbndp.dll new file mode 100644 index 0000000000000000000000000000000000000000..af774bbe0f7706374301fc4cb6f1718f13bfa0a4 GIT binary patch literal 732672 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

b_^-pZms9n#W6{fj#ZYIP{y?jSid3 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%0DTF$d= z{eN!X>?+3ipg#YsO%CW?Ij7I{Vipy|zGEM@m#h#vV5U3DzaDn*Hh@-4KDWTSB{!~cJ$Y8jz0XxQSO}XF6ZSe>bo;&^UgvI)NEt(soBzEYPR$u zHCyuko`WU-yxbksazq=~|J1KMkAqm>IqrD`zZ4PyGz0mJDqU;kvEi>7#rFYqzr9MJ_TWo!PTP$^2?C62jj$WoN zo4Q5v<*wFAFS?`jTmMY3-vjC6_K0%FF|572zW>vF|90e8ZF6mDyWSnqfM0m!80@#6 zd(iH8+MBLV&WDx+sqft6MuDY+U7Je=xe|SbxLEBtp4UN%*Le5K*7xz_F5e?xGe-zg z_nYnN%iRl}?BlC1cpVYs`{+Yvq5(ZbANo9?pO-M>4XEl5x8KgR#ohsXa-Qudko?x| z_w$7=H5Yq@yU~_7n_jos?u|LGjcv_$ee#L0JC1QvnEeO&j&9&JKtSW5?E&?^-j$tj zDX(}rX3m||*K4IqJtdEK7lYIy#@G%44dhPVIiM%fyfO}G<5uRx0S%U8+qRU~h(T=b zGG4I+)Rs}yj?X=X&Xcp7JLAQa=pB@}m~&bh(1TD}K$E1zYT9S(>mPDQ{->OS+}Y?n z&0WF19Iq|0MaJh-6E3#mVn_4tbo8^(!n>Ji2QBc=fu+}Ocjqek1h2<})IFdP0d;+u zd1XLPL3Y1Qz1)?4s>PK(bh1nR<|kf-1to6Xf!_uX$iI)q1@v#nn>)6iH@jML$I8{OZzv`&vSx32ZdgYC-mb0F7 zsW+{1G?jhW7M%QuI~x;)zT??w@5bp19Gy%bx3Sz+y-lw4zg?|Y9(HA)fb8CGlA8NV z&0orXuYJ^&SR>S1Xzf&&x(9c>ZA&Mf8n))6d9qtN{3}OuFXNSGaMt!`zczIi*T|OD zylSwqevEaN9(c=9w~dY>%ySY!Emv*k6?s6XGg{moQ0|_|-4*}V6L;r~KM<5SteKOboa`%3&C+5z5uD|&A@7iD=xhKS& zB6nAOC}UWAdFBmU=B`KXjz5(rguQOLJ0rWba<6Z{kNmcJ!ig` z5oE0Nh!Z!teN@V`qVEPgu-|_I`jA+`JpZY2HL=bC&1YQOBcQV;@~&h+7gswvzRDf1|Ca-g2vT2U?rpFB zBxdWjRr@^U+EPv)o0_{GQwO_P?m6iHwIy5j19?h5FVAy-?CcZlEjNmmYGoYb2 zx&6L8!L|8=2A(rP>gJb}IxnF4*E!lH=~}-xskY6d=!sQ9zEe}KmcP>Ox&O+oJfnit zoBwdBFR>4MhTazPufkP9KA&y~C^ut#XQnH0|4>J{ndL(1CD$?YwMYKRR+n!l&VhYR zk~=R8WiFb#Zn z{PS$jP(-L(2bVg9S(VLKe}kjVa;L0ie6gvyo_(yGp}((psTWRi)FAZmH7=GL1^mD5 z^lWghwj9A{6#@O*!(j z%G@tAoN`oGnZn;&dl=SHbR7hHV@9?2)ELFy?&#~sQiA3^Lqp^rF@lY-cvLd&I9 zyD|Qq7No9!&e01(<9NShRFHb7&{jq`TcVJ2V5#9%cWfUrme|-+Ler$pOBV6`4eIMN z*p=}A4xl|lKTE3`zTlZ0f7Kv`+fYkfbJ${@0naJx%)Rac78k4U87yzbtV4mcxta;?iJ}28Lx7$SJ%Gh z=7g`v=y=i;H+qlz-Ho>A2<1Lm@!PyTXmjqh-$jf=w)Ow@{Sy0x_|NZwE@gBKGxua( zq224o|NKPs`;~nipL?3_GT62Ge_!^0Un1AD{j<>_XnpQ#T_DdCf6isE$F{#XyFtD! z*?B}8^((6pI;d^9U6s&A{boW$e#iY-o@%4^4~2;wfE(5+e=u%XpU@3H6gTP! za%t8)>;WIeY6n)E<3{ySC2(Kds4`YR`0JDRg3DP2;jdBN2R@#a5d5V)+^}|GfBX#A zLKroYy&2X?9DMmAi7*-hEeyhM#HFk*}qZuv1g<1XP-tr zz}}2{ko_3-5PL9c26Y=%r!K%BR#kXXjm1}}OYoJf=P+uOx*T7v#^Z0OtME5j-(l2S ztne`EZPs`gwMN~DZ(^N?;m1m<@vl@3zL`}XMzyle!>F%W>0#72YAU{k<1p%5j=-qz zXuDD0(`v&X`@RqVk(L_u6KynVE3Gr?XEhW5MLmk|#X1blYLI&PK-OYtbr5b?1M?Vs z2yXa!g1K-n+^8d2r=itRxKYQjRztIjWIo)N^%|@iz>ONfnhmXv!;LyYFT_vOi||wQ zV&bRbMxCZ#fKSJ{Qu-zMT%0SVUxCNqTq(T-J|8#gGQAAG95?C;-2jirjk-xU!V_`B zmn~m|t8t?y>6Q3oy$ZiYzkyHDZ{fGBxHkaaLd z4Ph0GQ75wohI@?_Fx+dV7$3(97_J5DUyQnn)h}9IjT?0hD`2#`7B}iTR>5dB0XOP; zR>Ej?18&rftcKC*CfulrtccMnfg4rLsu-zwK1$vz`1s;kI`xh&b4EW z41XaK=i0GOMyshfcP?vXxN})4!xdzm3|A00>KWF`XtfYG>RHyyXtfA8YN;6nFT;&W zn;~!mZq!;c41bpuHC!XysQ1iC@cXz?AF#^Cs1MDl_~+(y;u~EJT!3#jRd_4wbhwMnCHOaH9KOX|j{jxG<9{3fuY~`D8@1hB z11s+uSbNvu#=9Q(yc_Y5HxbYCs`0Q_gBN>~@guz{lsXD$boFZC{y5j#n+hL?bFIBQ z;Nx+l26@xq!8ljnn+^}fjT+|N0}sc!m%aPo6LF(X@*aRs#*G@`Jp`YE8+EG3->6ro z;YOYA&4kau8NIzn;WKf1lvfX*g)@44Dfk?m(c60rj^m68-dy-xoH4;zm_@3*d`zqsDp*;fryjF7Xz@m*VtZZ!vrsZq()83-A@VQRBUr;45)@ zwf72qHBPVgmcZBI^lEPzJOQUydkydnIKA3ygm1#>)!u7x0;gAdE8&}QdbPI-o`f?Z zd2hhC;EYJ#Tkx$oBa*iUz702Os<#%t9p?$F3`2@Lf1hDDOk~Zk!R!TMyrh z^Mvv~f$zt8LV2IT58^zbybbUSoO{G;h9AZm<-8X75u8!Z+XN?Zqw2k{;90m)DX$ft zjT`lt_YFJ;H)_83E&inUJ-*QU5r5g+iofFhg1_o*!^W5|z@Y^`gO^;Dfy@PWv zd+p(O17GLuK;%8I6aK!pBmRN6GpQfqMt$UUf!E_kee89`Kk>TZ8@xU6j8}{|dnNc6 z-d=c%w-3J2>w$0b_Q${Udg5Ps2jQDN|JzutICr<#3;)LJjc@Uez`ym5!vFC~aUJSI zPJN1bjTsy&pOi9~?Rz9}*gg4-JjNhlS3@hlfVvCxj~S z6GN5wNul#7dos?wAG!cO1?S!mRl%p>-20)i@EJJwe&`bTOq_c^G!8xs=iU!p4xfW_ z?}x_2ah!WUbQOMX=o-8-bRB+i=z3Bw!Hv2!bR#}4G?B<zeA7V|Agj}e>-kiXfqG*ls6ymoc9#IW8MP1OWs0!*StmK?1~$;Ti#;0 z8*bF@c`v|w;6_FBUV@8p!}srAflF|n-FZvkgK%bLdCTBKaAswB4R9~qsKfFa;oi7W zhv)h4ha7?P6v$f%ABFQx!@N~+DbCC-?+v&Q&U_&6E%;d6s94?_xD01*khc~t$BpWr zw+^47ycaQaW)C-5+w{*(6^eoEd3{M5W={LH)-Qb*y; zEAlqMXX9Muysz-9^IGw1^1i{Z&HEOgkoP@)ecq4wZFyVqsd>Lp>UNwFGH)AvC(g_~ z?|1kCoSAvvpZG(0f8(?Aw&RcGY0s!Rc^;oI&c%&-DlZRzIxnBd0-XMkR{$@>nKR@? z@I`rT@#pf|6JLxo_siP>SK&@XG|m$_yd&)4JdwjY!+AJQrP5@9+`C566uN8{x$`eI`5+egWt8Lbw`!3FnC!u7O{{ zd18hq!%J|UnBgh#GMp!7xE5}}d18jA!i_jj%%@7vaa}FDB<8obe(51$YR~_>lh+JPc=i$bSVs z0q6OWzXU!B=ha94GI#{e(uS|6>GsE@DDieITZB5e=6urWGl{l z4h2WRzu-pwT5uG+4L9nyf>QW*oabyoANWt4=WM~T@ZUJk*@7~7JI<(ESPpBPQMYga z?BR^Mg#+O{oKd%M5T0K+1aDI~3@<1=0WT^%3GY!j0^hIjRPyhSGl~|Tjvre%l1L2a zoua}~_+^D>6S*AcJ%_^4`1ryK{K~>g{OZE<@cRlcAkY0cqfKEI{2+IEgdgE*uZf!i`E5UIov_8J!BRf#=|iPKDROkK^>8!t3ED zaOUBKH^NWiJkbg#!cXHyEhwyppTU`*7uLYf;`Fz|$?$VH{jG2c{5(#7E3AcI#Ep8X za4P&VPX8~w1AY}}K3_NuUW#)^6i$cJxKRy-_rS|>qZ$kEgPU-pUMqY6UV$^8FMJ4p ztFR9LvT!ExuW&}2!bjm&oPJVRkN;Je!v8LO4BuWj7dMf4xEGm^w~ai7?+{slcZ@8= zJ4F`Zog<6!9V0K`J4If?caFS5&AZ^-t&t`0t~jreBg^1DaidBi4RCjycf%r$@ZPvl z`$S%Y_r>Wmk(Ka%xKaB@R>240jDC?f@IxbS;fF=m;73H(l6oZ0Ts^W5J{o7n6?q@; z7x@q$5Lr+BIGnK}@(FxA&IlR#3?ClZK;#6R@i5X1pM*1minQQoMmFK+M7|^-v@apBc%=ABhy;$w&lGMcU$XBJJ^cksa_SBAr-?JRj#- z8QBqE7}*(rF46^G9O+8x^Ef>%(hYw#vIo8-Qj9N)l;G*eUik9JK6qoK2i_FfA72^i ziN78>2wxpJ1b-{i3x7M(n>yFvM!gd`0$z*rOpF|be-J6f*GKvg{}|`l7daOG6gTR# zNE!S&&ZrnE$2Ud>;F}@?iGPVR9!3Vin{md&$Pj!>WElQ^kyFXJ z4QEV?oR0q$8HsO?jKcY1C8-)`)G8W{=NDBFX@fIT6;;B8IP=4z^WY+!K3{YJ+z#hm zzM?9)1I}GgG#2iNa~Bj{0(Zu_3yQ|UJK@{~MVG_7;M@g8Sx)1MP^Z}Jh%<{Qs)GmN+#^LZ z;UPFr*rG?_VK{e9Q9XPD&RtWKf=|ME<`yyQS0ixlprX0>sYUaMoQ5;6D4GwSfitft zdI~?YXaRm!(L(&}qDA-xMT^OEAyI=6{+ilD1rlRHuKFQhB9K~lcvrQkqk$SS%htFXq;m4`B zLuZ5rs>||*@d?c_;bDBgG@d__&ttAE7^lwX=`)PaK$aF>hyPr7J^owajeJJ&X1heY z`}n<+iG2R>b^B_3OZyu9yY`d$q-56)Q~0Lp;10EFt{UE9Dt=;zJMfb`Ov6vy&K;)VckM78zk7$7_`N$kir>FOy;`nb zCFgRrbcZ|eGXnen#i+UtsqaM+Dx8C^)-1K)fQ@NRNs-OQT;%kM)ebUUQ@eu zoQm(>@eVxNaT>m7$LV{>-ZG@N5=)KMcveCA)o!+)oBraH(%vCS^u_6IsV5k1Ngk8U6*paLze++v>pzR z)+fSoeKH)^r@$5ZG`K>a0iUbSgwNGy!Ikx*fzR$ziO=bBp1M@OP0ma8JLDXv--XBN_u$L)2k>S3BlvRt zF?_lH6uv@#4qu@&@Ob?NJYH{vuhd_{SL)61)%pkcYW)*@t^N(ZR{sItpu@YC<85{w zpl;NK@Qu0%zDc)(Z_*v$N%~-Tl0FokqWi*AbPT>#_k(ZM{oz`D99*l9hi}t^;oJ03 zc&Z)_Pt_;Fx9gMP+x02%9r`r*4t)lEr#=(DQ=bJ-)91j`bR51*p9|lm$H3F|`S5go zA$+&K2)zCn&^{enqy%e6Q)9@pDIsAxjf*;i@;79fAa8j>^llo0~mi`rcXz& zcv05@>T%r;eq48e=jo2{Jlz>yppStU=)UkXItD+Z`@zrZ!SJ(sDEyp01%6JS2EVKm z@XPvUc!|CfUZU@Um+2YsGW{^TTt5LX*H6ML^vm!H{VKdtFNIg?H2k_=4!^FO;8l7B zyh^_gzoFlO-_Y;EZ|e8pH}wbbTlypTE&Vb4w*C};TYnC((HVG+{sMkSZ-n2`U&3qk zW_Yds8h%%Af#22N!SCr`;rH}!@ca4?_4gOs34u7tr@CLmnyg_$| zGkR}0qxXfI^?q=(J^=ng9|(V;4~ARxp>T^n4Bn^@hd1gY;V*Rz{!;gYzta8Tuk>+n zs~!rs>f!L$`b79^eKP!mz7+mJUk3lEuYiBlSHeH(tKpyYweWBHLHIX41O8Lbg8$UB z;lK18_%Ho9{I`Ar{#!o@|D&IV|IyFD+x4^XcKsZz%=54^FT&cq3~Tc$Y|K*Fm^AE} z<*;X(;E-7Xhs^76o>>j&nK$9Ec^eL!ci?>UE}U=PgA2^3aDn+8?r6^GR*uKJ4N#rT zxo{^l2JURmhdY}K;hoJ*@XjUy?_zF-cQKRTF6I`vi@6ov)!YW}YHo+SnmggH<}P?Q zb2q%3xfkwc?uWaX2jSh#40w0*Fua#p3h!mo@ZM%QytiqB_c1Hrea!3dzGgMNuXz(L zHGjaR<}dgd^ACIsZxatteT>LO&IQL+Q7$}Likuy1jkG}IA%J)Wu_xsW;(Q$Kyv_myg3j)-W&`M zGKa#0%wh0gb2vQM90?CGN5ezRG4N2+7anS2@G#R49%lN(!_9HoZ1e(3qu0?ph#yc?ThPzwFT^B?`4Q`((Shg) z)E6CxPDW><3(%FQ8r_Pfq5IKHG#kxFFQ8>;C0c_%K%b*c=tt!LW&=MqqViD()CEP+ zKIlNy8y$lNprL34Itx{zi_mrGW^^x_iDsku=sC0mtw3wgN2nQnjkcmcQ7FW(;h>$+ z9%x^52s#>-qv7aubS@f;u0|8lt!O%$fl}y6v zpluy#XD5DB2K7Vdpc_yfdK-O*&g#s$Lkm$OT7!1ok+z}%=mzv0T8dVphgnChv;*3{I2v5lt8<6<(popH=2T$ps!JQ zH?9pDg)Txf&^)vhtwC3I;}^2fQuG@71Z_kGyHgiB22Dh_pvTZUv>ENN2giuUpf*u{ z{i>MX-9e!}`PCj&P(mL==b{_X0<;cw?9O*M&=Kf3G!k8a?nd9BgZE-wKuzdtr1s`| zqVv!=Gy&a$?n2Aa0sC-m&`@+1IuBinu0aWO7kUWw-Iw1lL8qY6=y9|jeSso9xMpZL z8jY5r57BmX@O~TvnvPyZfBZkBy$hV=Nmb|j@9LgmW_swJnOzm|1ZzITu9~judB8}Lm6=tQ(^;9-nOWUkfTEycqoXdu-~gin>dNZM!mfK~L{Kif>w@kD z7Fl84b=Qk`1%*{s*C)%|@9)IpANi=65$jVC8F9{u_{Tq<=bShZf86-jQbSs z4{*mu89%slxbMOJChkkPuO8z@JzN8~hkGUNW4Na<>3#+7+i>^cbh_euaUa9|KJHI& z|9FD5xCPu*+=IAZz(iToPYQ#+%s`!aJ#r4#r+rD|G*u>mioiE|AAZKM952Ud$_mZejE20+%LY--hM0N4ELcI(O*u|*0_6dPyY_`!TlWWdEdz` zUIoT6ZVPuA_hYzs;XZ?#T%Zr&z907^xHsT_6L+;p|HQo$_a59+mlzkg+i`2S*Ww<< z{TA*&;?Cd3GjO*oGcIwr;YzqS;eHJ_b~`ZKy|~M`SK)pG_wRAPgZsNXm^)6h2H@U_ zdym3rsYl!o;2yxe5%)0eb1U>o+%Kd@hx-if(mHcL?$2<4i~Gv+)G6+M+{9h93vL;=g}Wbj8TW47qqx`H zO`pQ8-$UEs_HnPq{V?t!+<(CR4(`9>uHH+(!>zrT^8`4IGqW3TpT~9YWBlM&zKeAV z_qvyo&&#+m4EIQxv$eP%*`S?p@4?+&VJ*RZU6sCf@@V!)N4^vPGe>suKYQd6{69YO zN&G)K^4IvEJMvB6aWwn8`a;s3>v zXX5|wBis0YdE{T<|J9Mt;Q#fJrxlK7e{UWO~T-G?RVeb|xS$IWN=Wv{_~Kkf%`KZtuR?uT$!aj(PuFz!ci4;(6^A1I?2 zD5DQ3qX*bP{@+0E-$35qfVB0eSrm*?V!nhI`+kH)iiY^dPeO zgK)nOW*<285VHD1*#~j|2KR3dy%~A^Ey(F_fir#!a`{`Zd3_5q`CE|1-+~POR%GwD zB6B|s*ZeRt_QS~54`c26Fmm<7$kPuaM?Z}G{4gB#Pa!Y=6ms&a`Dd~5C1%J z@XsUvz7x6koyfcIM9zID^6h(&Yv04A+V4T8eGjtizsf$tjc}jE{W0!OaG%4D`16Mz z!FKi$EN34n_7P;)N4Rb75jgipxNYtcZku}qo7zW^W8cedbMNK0x%VN*egdxk z6UeQ+xTlPKiW}%Yg^c+rZlL=t_P3wq7P`-3 zf%{o*qWfEHaQ`m533v0zmykWbgv|LRWX&&OkNc(UD{)_idm8TPxM$$L8uvB0uf=^G z?(4DVMY=fjEZjF>&-;zIXLEzybFk8VE;rLX53Ag78hO^CZ^qvBTd-$+K6b3%ihBX> z1nz~nQQR1A95;cR#7*I*aWh!9&f?~9--hk#w~xH^(5+aez6gudleq5~*+2B1BdbgX7DwK8XldjfhfagPXx@^zWU6(!P zXSN$++8eTO_jEVLv^Qq=d)TpT$)`P*-REJ`+0)=9^!L#iy6#YbJu`;BA%?!`(9^!; zQhbYrRK9OH^gPaf>Tfh+$75*v&pt&_)bZW2k*Nyl>Y+Dt-5G zRiZI}mm=&^gk6a#ULLV8KOAc4dm`PdBi;AM&=1BGKN#tLC}LlC_=DUSr6<4caH!KC zv5;Ut5>xzW#Qu21{&;+&*GJgvBkTBph<&SJ zL1zCVV*g#t<=@B9hhvHlN4npR*#913e-=aaBcWAa;X_a38=nF8`Xg#B)yC_Ogf@CZ zguNlc9y}6y;)48 zQ}*@Oy3*g2Ju8O3(TCteuMh9`V=?sWG4zh30sBWW^w}8tlNfr_je+iOo*F{`Cx#9k zbFimnuRRt@dew(+%6`~mZ^|BsbRUa!ACGjOh;+Z}Lr7RL^tH!BdwhKiJtu~q7ei-a zXeEa3jiHys(09eqYh&nY4E;n5y)lN~6hr@43_Th{zkWQ_%LiiUHzW3AG4y*e^an9? z{Y~NBj>pgkV(5c0^jk6Xu^77f=JQ{vae}mYbI9d6G4%Y1{q_he#L%J-JuQ3AGeQeK z&xg>=Sm^6V-grHd-^kl6oG+iTG=3l^n`4NS;kGu!}=;7b7@F&gxee?ei|LsTq694pZ`De}lcLw>5 zBkg0zWru$qf6Dxik0`u&_#Yovp5JZ$Ys~*M{Ev@3_a@}F!}70=yu|$b&EGfwhs=Ky z{sV{q2>+qOFT5F9?(l>7W0q=fr&io%S|KlUu{|K4u zi2RR?JYfF6#(&X~TmP~2cyBlVz2<)kf8vO0Y0vw5uU8$Gzjx%9zd|LK|Ek0Cua11m z{Lh&GSLRV)@aGKvcjhlWO{vb~?~T0P{GY`i zyXIX_7vux@E7z=`rCPb>jrdnbe%AbdY5xC>zj#7ytd&s}3JHd@tdvBis1Tx%QXLf4@Qg1OEH3 zS7~2-yz%wOz2;vXc^BcgAN>{c)hFM6RPXinqaQGc=-+-+&%!tO$ACY4?SC`>5AlEc zT9xf>=Kt|gg+G1m*FQ^TD4V}){;Tj;uK6bx{u%S%W&VfpAG}ddfAB^<{lOdc^apR$ z(;vK1Pk-=6JsscR?&%*T)x+0*0{_qLxu3FeH+Ib%zk#=Y%DeHej{FAx3!d_M{Ev*R zf1~=gSKFFfVv@ZUJ{8~BH=eKY#L zt0Vs$|IoD`v+y6{fAOh$>%TUC;mB7$S7ZOT@jpIt7ka&qkGu|l;yMSBKW4rClQwo< zaozL3Sx>*m{5t+qY^0yI*7@|ccYTXm>SOr7WjVa+uyXjT>mGZ)=7+g&)yUn!|Ma!L zfd5z5{iQ+vpBD(LR{pN*Rkpvn?z>Ki=3V#?9sW4}Ph2nTJFXvpA)52+Ux9z$arGb0 zy^YE*;eYztpTd9W@W=4K;s)jO^c$Wsh9>ZaXX8KTh8N*Kba(~-^zlveHAarw=(sxa z0FbLAZ#DlH&Hq*WPhb1{_zxZa3;adP^Nt&ikBjm-=1=19+~7*`MZ&MW;aL;H-fRB0 z`IqtEbic<|XU#ul{$1wR@E5Ye6aV{;oh{0Li}~-xAM>sMCxkB^8(EZ(F#!IU`FEIK#((tKkD32Y z{0|-bPx!xk>{&~C?lk@@uDj3t4g5bn=2q1Q4f1yLe*u5*$iKordRYF|k^dL}fx~}+ zfAQGYp3<85e0-j3{@v!k%={lS|0nUckNmv(zhsd2nEzh$|CjmCMMrw^*bB|yGXE<6 z7oU1`S@7rLFC70N3;!to9moHzh5x7dUo`)k+eLW{|NQZ9!~dpdXx!}`e>34{KST4| zbIo75=5s(^d;EEK$REYuK628+4g8D8UT6NlH2*{RZ#sVDG_&sU=itBZ_yzn&kGfc z{6hT4j$bkVm(Bl8{ENr_hxuPL|C$w*`D^em9ve6R+wrfCoUw2h|LHeT=D!O6Rfjc)zv8+dCj5%)G$+6B_(ur8@AzNhUp)5AJLP{f z{`-#qfcZaVkPn;xN&MH`^p)pShGqQIHcx)&*aL(gJO1y?|2Y1KjvZPP%{2aNZu&+1 z|8SF9=QTGSUKjS;@IQOg_u}7UIehk}Um|?-%}+Tm|9SXVM_!8mV#8iM_Dh5>9{Uvj zPh78=`6V~sd6)8Z;nx$c-~3DXFS+@{_#ZmPk^k%!H-8iUYi~Y@|4(i{hyS5tuQUIr z@h=|xHS<4W{wK}<0{**i)_nWe@vVCl)~x%ehx}_Gj~e8$<9|c=n7z?s$B*5soL_|h zv77I~zj&-{{{7~EFaCYUHOl_m&A&?czuo*{gMZrm&zb+f@xO5M(_bwA8}L7Ltbu>{ zmS4cX$JUy|xBLp>t0RAmfAQEiq91?$Ei2~Vga4)*cJU`}c@6$|-14*dciix+_*X|h zg#Xy_|BZkC7S;b_$G--h`iG7!n|}`f;;{?(j~)L-d}et3*WB`-4gP8TAHL;pEqwU9 zsQFu-kN;0^DdE5Sme=Axdds`;KXA+M;(zFt$M8RP%ky5UJeTl)@0R;5{C)VZJ$`>l z@CVF)$o%)1{~yi&J@fyM`PaTol+QDN)chs$Uy6V9u;%1PkNq&=M~}V1;GZ!6bLL-P zR@!Hp-!lKZ&3~u)A2$DU_>Ug@$_*r&e{|OT`|zj!(cAD}d;Is!|0DcIk6l+$Zu9t0 zzv(RgqsR6P^5f?JQ}f?%{(mz6i{^h*RlI?E=EY;T6TWz?f&Yb@Ux)v(o8MuON6r5T z{xi7a;j3}$xGJuO+r;hRF5&iZFUP$N_jVkAw=Q0(Rrb2I;zqIDEuX8EtF`vYYN<3f zI+~SAYu$3UUMaNO<^APmy}Q1@TU)EYy!N88(d^a}l}fkOKDkjU%|M;qdPjAmS>1hs zXl^SvtBrbd>jldW7-6-xCljRe0*~$7xmRoNFSQzt*5z7te*fePR1Q~)?AA2AR;yiD zZ!NSMdpk{!UnNbuqXOLBu6JvvYRy`^UJ-Kq@!nvP1gBf&s@{5|+^H=$H(QqD)Mz$7 zKQ}!yIbIxHniwA|EKZLuOpO*7ic7`9;?(rS)cEAs^u+8Wgtsm=_Bz{2HanUXixY*# zrNu&Ver%yQJvOy8F*-IgGd;01HZ?svHZ!-hxHvsII!~&Tb5_6bZbNII8m0DyU1&9% zwMw_p*>6@(Zk0+4sbz~svI}E^_J^R#SQf>Q8;-1fd2S|rRy)Phm!BC;kRnt zk~)cUbddfOV{A$_zb-K;+j`hd@-nF+in*J;tiR;!zKp$9bw`kvPz1C5>@o|@s$G8v_HbXBq zYCH6x*!_p*KNSU+Kvq+gRi&C%?{&$Ib>&});{a2$#Ckri_LD^zqP^oE6V{@-!rOjoBPR) zG2@p3KY1|D&eXcwE$g+8)@Ctl220wXvm@$q1(TAj4e+1i!vxmsth(RKB@(roOD&S9|1Td=3I?ichllIzrRwi>Ydly z`?R;_B#QmY38S+zTWGD;tS&U_^wZmFtoK&jNHWz&lB_Z!bZF%@n-I1-Hntq7zr|wK zHXL`0`wT_612O|pY~5Y1`_R+vRlQJUu$kySvxzZ6(muk(3X3S3Mp&_B}4rNnBHIY(@~LQBw#HgLo@Y? zA_w%4ENsJWMZCp4{&BeTu|DpcxU~kIVT`c2=;da@MFUg+xr6T2!wZjPXIjv~QFv7kqqrabaeDdTL>AYH4n~IJ-Dnm?%sx&5q6%CW=$DOYp;!4}M%aaih!>AA7u z#3WpFaeirhbZT<4usAm}I$JFAkg-g?wX4GZLLC zEEsh%;oQZfxw)^*N`}(NvB1>K#NyP#%*4|4?A*fC*zEY+QekF(s<>F3oShmQTb!L) zTpAr)7|Yh`Tg`Kw^6DK6Yh#(qE=ElTfL*2vZ9YjJ9L9$xJR`{GW*QBg$XIqIx7NF{%4j zVjwxG2&_To_co1qAn!S4adMVti!V$UA^-!7>cH9rQU6-vGP2i6hBqUXDQ>;KQ)}&Y zH7b=d5iJ&2p4wd)2anUr0LjTc`_U|s&u&IC`ZCahpRRXYB7+RPAR>w=2jIv8L*Z~0 zg7=lyU~#Sr3C9CvkL1M58A9Y|_Zp4zMx&-8Pl!6?F_lK9)5we>^t7dVtx<(h+_S_6 z^*WKIy{2Pw$#ga(HC9`XnFF$3?p#=C?d&#cVusgRd+kaMuvZp-r325yzg%Eh=m9RPM9QcK>RzqhaoI^_ zp~pJbX@0NXK(VCf2oVd_kF_c@zQc$^&E*i!imcUD=aES<;z2Hj$C+qcRnb}8c=&0%r!c5jN`I-czn&mW%x{=&^0-lGgXEZ zYiqSFiETueHN^BA>et8nULtwzrLx4}ebVIbGZgI#HxyN3)f~&TNQ`CG{&mzC#$}co z4egmy>2kZgJC=27m0h@kwhN&P^P%ynX+j%&o0~O$59Tw+vT_>&&DN_IDxI;cwYk}; zb;q*(CNtAmc14MIN+o#Za-*?NtdH+{9F}aM)vj@d;qQ?GYL$e=o#iz1%PIxX5{8;7 zo#$OV%q_w(@;VISbFIrZTaG`D(sTlHv0gSujc4=q?p=(tRvWl-JkLuJv^VwP^_C9^ zpP*fkxyuC(<^-pBu7b8 z^0!7=Yf9(%9O^UhIb@YDxbQjtA?V}?sR0u{r-ybjkfK`w!AP-1(;~LK!*l?rItQ7K zo{VN7%U5|&1B>09GOBKzoMLIpZf!NHK2&M#>`?JOwu`p*a){JCa1Wh|>4{ugy*12) zN4C+L)SJx1KE6$VsI|Qy;}YyL-$(tZ12vqo)J2-Ltri^s<)UdRd`6v4qbH8k-`rg-yl1nCAV&R#PRRJQk;a0xk}+;L2VD~OmvIt$&e zpQQ!b&-4kDaC4?8W^@7$lM+FjLNvY!i@(#)p8MG>l?u&PbAP9`*U@S)`Z6K=p<_d# z<3phnL!pyHp;JJ`RPp21#ywVXBFnBqRyGOWQQJ4%YPsH4)OM8y)_bvytDQ>_q^ooe zT`tzG8H)`fwg;+dWIU_lGpS1~X4oMH*T%Cmdkte(#iNa9_e_n>C1Trn zuLSDnHF}0B*sq-9er+7jVy7S1Qpl=P>5OL@Bs}aamYeO?E+8`# zu5~Y=7A!;6=-N-g0Y7w+`nO#Qx`f;sh4EHoX`i=1V}cT04Ln!L(gY$PiQz#WGwmJ zR;ATIKclrmlzy-h^l~6vmTB~1_H7lX1mmNVNioMJv$?UwnZoo0njn;4qvI2kh0!q- zVPi`RQ;V}pQwvkG^Gl;_9s5+$;i=dF^xk6g2-+5mMy8(xCl z=JZ-H=whcziwniu7Ui!MN_Q`>-&QItu9e`~OAGT0Vt-S*CrP$gI`?EUdon~rOLl7E z%#$hE5V9d9>!VU-3>2)7MpgENL{F579#mXg>#g(TL7LC<>PIi>BT~MqO(M_kRGR~! z@sdEu7R{>fvFbE{7U$4Jj*U;vOf509&y9}HElkeM&o9l*&x|dME->HE&Q32CCbMKj zG6?Rdwb_kpb?zclG03pkg!*P(AnB}2bYp*Ixv0TTcuzahahe5Sb0ojaN97%p>)bBT znU3+aVCp`p&1}SXY){Yw9RuuVI*>NIdD+~PT&S_j-C(0jbEwUC(7E}}Phi9~q2@80 zqk!g<8IgL&_FF<}!mKQHntL}tkwKbNTkX`^nra=WV_BZi5XNnxydc-1bY8HwTdN?W zv7%I8kcfx5Jq)>rX_8=^CJCD*N}*XzVVd(M-JCaRa~^bIcALzWS1%FQjz!3FY%0l9 zk>yTtUOE`PnBq(pEN(6tNoT}37c!)fIfE0${Nad?4grOtb8vWrR5S&+Uv zuT{#8vOREaDjS`fnxB{&TUs0+8=V}Vn3*4)7@wM)9-kdun49H)bh0=xF}5&evmeV# zmN03FQePN#Y5k_{Xert?R{1_mIxr}j9~gxC1_qFHU=X#=YD}$q5CH4y{I+YA8XdNp za(scLiT=;YIS}^97{o8s_C1~NjKKbW-EO|sLKED~yVjG>A=f4KS#T}x>~<65Epm*# zkzTM<1rWMliW{4bYaqe6x_K~5T7bGBozMmH+{dRAQ!GW;+Hj1G^~-54WSGZ@YjJFH zX1=g6UYuNFGMr@#X=-kEacXIDdUR%dzBoNe%6v~7$ZdE(I=n5fis#@MD=7D7E5vuli9S^QsR;i z>TZv0##Q!0qa~vSYYELK)4=1LIOB=JUaA^m=5ZPp^0Xm{ZlV+HY}cxH1lC722;9~e ze!Z3Od}eNTrifwi#QbEjIJt;{#Ki34%xpHgR2-X~n#81FbQTlj$;Ek;@5Rx@srjY( zVgVs@4js;Xan?AP^Xp4IC+!+UpJclp*f6k?dBc!j==KC-eS2`)Mzd^0RSMN=8(fd> zk_sN1bJ;}MmpF@gzEF>Qf^)S>t8HyE0mN);lzejTaT)<6RSie8XT0b%QO6RS?KH_} zfCM8cg*6w(wwVQRaxPn3nwlJ)M*B6rG`dhIj21`dmKGKkW{dpK&d)4NEKSZVPA@{7 z);7_9Xl<{w^U5Z>P}u}yWfS(?aM+fn?wnqnw*$+{u*U|tY%}VYU|*Njx22OYJL6)l zTdp@cC$q)r@xo$Zc4@pgGd^3KViTuO99x(eou8YWFOC;5u^C&M9UChkJdV##%oS(H zCniRx*%q29&J`Ali?G_$Q;XAd)2Rtr!xy4zp`Q(5nF`!Wr0H9M`$-0t-+qF@wYQ(5 zXW{Kf4y?NU1P3t_p6fd3Jree1IG5N@F!&z*6g}_Jj~sZ9lt6iVWlEO6j|Hvz9gzHO z_9(EM+btEcnd#!#6n0lrOH*@&B9qI~#L~j-WMOg^MeyS2(qv(FY68uHB~k}1)H;g` z^Oib^ig~a;o1oLU@GjAOHoh>wI9_1ln^~9{omiM38=ab+nH`-gOpGs%PEE`gWbHLK z#SNux$z$TgeGq=g#pV~X(bDqpVs^GLIW{plu`s*Hy`>9Q zb}pNy3|w_OH##;oy0El>j$~$Hnn`wIVVuB{q=QA?dvUBVM~2z**}F>TIM+c2XYlm~ zC^{?`{VKk$Er9@x5i{n9Bq-@=jToV%-jNOTdMhNts1~@hsCD6zX<6){ ztN!8MgqxTO$gQpm?8A=FPEStE&&?Ia=SHXJXUCCl=4NJR7SR492aQj$>e!3jeQtSu zF`FD?>~p|nW@-i#J1ED96-F__D@>2lMktaBV>5-NZ1vnyc1j&+t*}(TQmd+eWpt&% z2yk>>1}Dgy-e!d^tSu}rrvf)(_1fC%a(4Fo>C;BBcIRoUTm7bjx%RqJfD#JCOJ{6u zp2@sT>helfToq(BE8dwcH!q>tt=*a3vvMx;!zRr|dYd#(u7a#v5xAF5t$U9}?#UJ_ z_hh?!8;v@@><`uMG3>pDy%+4g9(%80@6Du$T7R+q!1C_w5=Q;MS1Xk$-sMtuy1cVd zEoYj<%YLKlgyTEHyQp`Z5L?-5o>(q!q#K0ZRJqkYLEWZ^uw`bZ_NsWFrQW1i-tVl{ z+3Hwqm$Onejk)zuhS}`EEnZ>Y1nVX271N^F`>IS?iG5(Ur?K;>RWuk`8m(cgE z?QOshRqWMO{qS_w$wPR)OrwiO6GDZs89q?O$o39s>sQv97V5j(wYGGenX?J$hn8d} z#Re!WIRLIxl;(9l?`2;2RW1UM4!sYu)}~(rxYS6;sy?s1)LQ^5%?t9PxPeE zSlGK*M%vzWoiVM-K2-7?lLje;eiN|j#R)^;Vk9B39F5|D^A>rLq(>Thn+iji=%qv@12#Az+sV8bF_t(i=XrZ^H#M9b^y5HOe=D#Quhj( zxjyw|PwAvnVzR|_BHdy-p-OwadAH&lb&)!UNnu`c_|gepr234;)r}_1!P8_7*+db{?Q|L7u{;XCXiJYfz)9v-$gpD^u#JxSHBgA#wg#~;|O(eOQC zS%$oajprv!IQSBSk2mdqXUaXbgM=*D|wQfp`BYL%1tG82by7eMr@<$ViFdJN%R5AzK>blJ**o_+Om zbUfX1@&tT%_IO!5(aPsd_bi`9Z5epkQ=wCc%58fDDs<4GG>yPpF<%bqsFOs8~YJqWs2ufd+HhLI;t!iG$@tQs20GE zjbpT3fySiim5Lp@bF6zWq#_wYX2+J}>2gPRW;ntaapj~*xi7$>u!Hxph3#5}GXo|* zAW@jAz>RTr@><&iFpFzls+qtOVJ=%wVEIrvK3b}1HqmfAfK>B&Sj86i_P4xF9RFO~sT0R7_tb zp#5vQDk5HH{)_v$*?~K~?$vWbJDSJXEN|9UI1=yogEIrCfbh6L;3_FkP>D$$JB|Ag`P)W8sLbetxI+K&bgWnNMm-Eo#(h+k12=O7^&@?W!kVQJ`o|ML++NB-O)0c zEoP;P4!ZD)J-|BAjx5W&%wNk)y;pkCNd~U^*3h6)Elro_COx+9n*0pEyX~4AirhG& zwL%MXyn@6FAnTy+!IgIKT8{429>3@1-FooZ#L<&=9X#X=58Jx6{ma^k&LQgmT)1U7 z)#OlWRu}a2gD)frcardK5-xYU?Ie0B2_y7dt_i4c@S@reC)+nAUS>gNOsy@j=qQRdbM_XPp{Eht+8ig9_MB{=;x_CLBaA zY;*W~5WI+>KhT>sjj>ZR1mQT}1M%ElG9=ac+zfr-QK$2hKm)i{ozT?CAHZnjb3li~ zLW3yIZ4HA{ZC%aZgDIF455TzdNCS^BQ@a5u`z1SNl#Q6-4d705V?bqJ=hp^tL1R3S z$d2I;(mOrvLYbY#L8L|mTd_7Z3}S6q9E@J>grok0Njbv=yD4$}u6m~~?an}Xm+Hfy zHc1cAx_z(Vxb=2@2R8Qrq`2<;_lILwx3qK}gc}YIYVzS&?cNQ?%AQgH;1(0ISyD1MZk``8QWyAA||GT9YDR~ z<-;*l@E|?hg7NbHvdDoVI*r9aSU(A=?FO@+hnpXc3D+wP#};dwVi`>m9ZsoU;1^l7X@V3rR^o3_PZ&UWH+AWuDSIEE!Th>v!i z%5W-ecba(vtlf}j+SM|CoHEAQ|JL<-gM_)v=(iRI3aWw0y&!IHSuVi4}RoP*FRUZMb@g|q`N85rvfZHEoX(Frz=YfI904o-3!<;!43 zP6Qi{J6r4S=p^qzeL9`eAUqD&6>c4n+G&u)8D$Q_*Dekrp5Gq|cH@v0yV}|r%*oZs zL0GNXYqg7LX9iQ+ihU4L+RDKs?*1d!Ne8iB?j1z9WCx;ik$Ff`o1D&J=HV{4pqmU5 zp-4pTY@w%;kSJDZC>gihv=2bp@b&jv47C3uW)fV6Sbba~D#c%_G+4fT7!Kl!Xr4Px+p&ThugT*#FU=sYhpTbGA4$>J4Q z3bn>y3B$569P6*w)Oz2MN!?(2*Zm5J)%6YTHK%WLmUWQKX5xd8Zj<96EQ4YXGdT`w zs;sKfVGr;`%mun$WuV8LZ%U=MWl9xgaUdZD zvx|a;=3)EW+*f58uD;{L1^_A)HZ{Uw2m?q<3>U* z91cnBhU?>!zs=n>ARuAynv$Wq3IRS=18I3)dq`rj_=8z`1}L91>=M<1JZ0B9Br%eZ7#-a_F_1*! z;vm#(^oAp~ge+egOk^v_Fhs0c+p!r;XtUiQ*ekkS*JKN2kYc&R<-%OeHHa~*+d*(( zObp%Rs-SDg$GZS{gEi04smfSScoXS+i?w$&H&_;YJjK1ouxU3n6l7avpHT_^g_s@7l6G% zNbhZ`LmLKgg(C^F98cr=wvQ`<)4+w8im*lzDrmVKUPb7Kqe1lj1umINX4 zp$OH^nR)|pxA)P96==^}$q(d}Bu& zz)5T`?)ccy$v1gKm&8hqxc!r%diD*##Ds=vt8DPOU)uE>cUA_!eXl#-Y$M%7z7|S8 z>rucERoZ^S)+s#toI)pjv6)y^RhUv(QQnP!drcD|_1-I1GNrfUoCAVY|mdnug{3Kd3;mfvXt&EFT z>Mr86&EC|FJfy)KoYx2Llhh_$*Ov`TLaXe(oKQLS9*EG;a6Bf~U%jmdpXo#K$0L9_&}o%=elzT~zP3oin%?ojx=wW1eFS zTOkj(5?e=OA>E}DZPazUx}~ul>8MKxFAip?Dbn)2MDz1&=H*BDLiu;4jf z1P)tAY4RM<$oFsNt`w?jPUBYFDL^(>Ay+Y+AzVk+v%aRyLim+<(N9*lPs#Ow+}1|4 zs113T7BE=AMqnE?5+^cQwvSb~8&zEB+~jmwN{^A6gMHyd-+6oJ#Cf zNYT4)Bx}`hg7}e)u&@L&r~cjuB4TE9zzVaYX8Ay5@2;LyYttm*D0RTg|8lP`=sQ1a3_d%4VU^VdxZRY`+;gx zb9=qH7faSl!RYKKF#DmjlrY=L%Hv<(sx`Q&~hJ$pZsWJ2TQlcTv~yheSL6fm$C-pKct63n7HK zfDVUWs=4rGxMmkZ&!#&W1Bv){w-1x8G)=qXV;VN)b}h_R*bw*4Ud+mUS3^L<80?1@ zw`;6dL4FBes4CdPG3sbfQ3$QYLh zL+7n)3UX8rfK2>xH%CDH6jJD}kFhlD=P5Bz(347?n7KMzuxBL%4Am?+sp(hE5i zZiFxcK4UsvD82Naj{`L*iqz5>pMpUYvLI;}o0saWzf!l}Rc_Y}d?^H$-4HaO%A%1| zxWqhU5Df{$O97WRbFf}17zJ9_$!!Gf4U=d+S`VflSV}*ygpAO!hjAd6CC`P$;oF`Y zUD+AZ)9vm0-Mpmzwukm;roLW_M2;@GgQq4R`=HgY4^u-vzhc7-~;%-$MXwH&dL z@0n4PMBL04K)HTXS`5XcI14mXlsmQRCtAb+a#KaiF40PC0VncXaMz@N3yMx`&Ss#E z5fi2jtm#2$XXc+p{g8r{tEG22Y~GYBw+e zY4G%csvDM-KlNr|B$`nPw!HG59oLEvD{w``&PHSZPJO2db*>q8TEWg&xfNmh@)Xhlh|??Gq9aAedIJkRE*sG)v7az z?ncAdj0>+~qHZXVOC8I$x)n;{L&B@~EKsCI%V9%Rq_ACw5_#a2ET>rB9%x+$Tj0@* zL}`LWtwyDNgFOPQ0MX($GhQl`QS(lrvDIS!+}<(Z_5eib-G+n_sO(A9a@XtGVaG^e zZ=8cfm0V^N$@*a>j5)%MM@CeM^1nr$x?^QmW>W?zcieBRrTp{FZiIE*x122kqvv?c z`21eTDX9cg600jQrIw&tFLMBs5nc&u2Lp#1&~WjTp?wojrQtH+88KDd)G~-}hVeGB z)m}^|Slh;wn(i3p^a2C9Ht7MCwkfG0Ic(*=xxRiSrgxUoRw-JA{4pYntB3c)R=4^g z)g)Dz!eZ{biIOubH8uOHk~F$4qThMI>kXkvfS9aq8 zUTx~S1*9KX>h?p{TlR96gwMe>*+FS{$_m-3?hrALMf;oeG z!dTtdMRmHswHY;H5vy?vEy9TJO2~*`KU+iXB0(rW#%PLhDzeLj#*nOaSFGb0Z1fyrfxO65|#h4!F$4{PZ z51>@_>3gACr{mCbN!h%WaL_|{N?bz^gvGu$e!-1bmxsyzzND5mlzL-7gj{(LjoexL zid9guFPB$X$M3NjgxtK<+8bHdcR)Yhwkvi@UXr)Ikv~#p}4wesf^&s=e7PUu@ zms-p6aRV@q(_6N})`SswV-c_1G*DR|2u%SS?mj3(N(p8G<4ZQ#a~7^@rxh^5DE(SYI|yf)%`KuA6wA?*VFU;po?;Yw|6YJQu+jsQ?E=$p z4~#1BiHEKP)4vfO?-UVfRDED_Jk}>F4(YnD@;i4BP;R>9U-_ z+pl9E18C9B10iZAL@7*FU`v2z3!_rM>4OB;%<%RdK2!ZWdaY*Eii;5TJe$#mId^Rv zb1j4DdD8cJ6`;X-^?xZwL(Yn9bfGilkln33tej~9+j%x}n_O+0$AX}%iRN5w%YLP~ z@?5Clhn(2b;%Pe~DIHoO${KFcur;9%RNCn!3Aw~uFv3n4qJ-b`>x64FPsA@C`%7T- z7M*Zg7t5f#9!XiEI~nq1ys{@h@|>C!=)=mO&4#M*RbTS zWw+V4_zW7(rCByH5+^GuxjB@E!a|>4$WX1Z16W)<7mur1CXQLiVQ%-^K9Xu*LAT3` z#r$;Jd-_oCaLTi-gX!)+#(ZkB3xuIrn|phqo>0JMwH(3091*A zJ}gO|TcOHM(~zus;Xa=}U^SH0A3MQP$elr3zua0yXh)&E-PX_Y<~sMFEMf%}$0-JW zu7Y6$wL2K2VJ9PY)`(HFq`Q9T1)W|xQiQAj7uZmXKqbp}{_Jt#^P!Q(HY#IGDUxlz zEZ=~LBu<&mPOLTgSuUcY6}S*Zo3qxAeV|gam&9+dC;HYC5@(efWjqo;0SpgxH+Obf zXHU_eAXVDaXf3D`(M?>J0d1~FKy%+mb=1kCpK&p98Vv&Jax;ahZ*XC6r|ZUlic(KI z099fV7?#8tA=dm>NSax`ACW>UN%50~M%BU{!g}+ttSs)fD%-cy2jNJ~ch}%2Gd_Ct zs@+daRciYuk5?kbnbmmv9_+Zbl%I+g`=8%u3Y#^-o)k9AXxRXu|6*+(3BtWSG>hBK zw^p+?+Pa1d^{7>_4{{@?&~$nhjT5oPj<#6a*xTZW$$T68d1>DrIL3uGuOYK~U3z@Y`r0e2!o1F); z##g#7taNk~gjdVhmnHU0wA3 zu%!FvsG#Rt=O(ixh0}BAWNt6AP5;T2tvNPPB<8>Y?MseYM*FJ6bJnfB`X$Gn;VU~G zs?@GmLnoMHRyMRB#2w|~^d)bb-)fLU1E0ZA%z^Pu+l;%Na{EG#@@Jp)ZrsX}AQ*|^ zY;R6Y>38Uh^PK%`Gb)0@LtP5@}v*d)3qi5IW3F@yO^iqn zNSYXLcQn^ zlECdjb5#N>5L-zJ#&08AieN~YKd87tL3`9!YQs?YoX)A?Xxq3ZO3^V$Cr-i}S=kiK zi>z(e8jS$+9VbLJYfFL5)VuDFF8HYG#4a25yV$yR(Ii0&*veobMy&n9MHY1sdrwlH z`&H(q#IcgN5aj(Y>=0PaxPVfr4t&&Dz&t8!=-~-PAE?rEp@`U3(*wE(@PhO|#4%0! z9#p>4528FWmy1dA!nvk!ag{EOt9aB4I@ca@A|sFPXP>L#6*Iks@cr72y~ z*J=8V*AgSSK2%~IXOCI#us=al*dtUZskz^yp=+g}pZoW;? zY@Yk8QL~go@&`%WSra>U5_y__Zi*w$fjVKR5~zxl@KgyVVXG3T=#AHAzXto%t!9kS z8}ApJ>EWw(RRfVT@b40h94C)O3Bo>*MULCB^Xg-o8c`Dnp(p4j8LJ!%2qJco&oafh zI(DRrk#2x03EgKq($g1g8v}+c-c@5y7>ZDGdbe@np(tsb%NKK`5tpy@5+`w~sv?qH z>N|Tov0QGaJHAO0rC`odN(Im}G?BQA6C!yZ$fSZk63t@?NEtcBWgo)C3pqo1tD1CT363uSVKG{l z&$dF;6RcjSa0#=^meC#RBU~D@>I70YRja!#_Ho$GGzpcW!`sxV`nG4d70P;djHrw; za!M9>=r~n)^%1un5<#Nv1920u3_2r;Qb`1h0Hx^xXy-Cw(UHIASnI3~=8lpw* zrE2XB0JM>LBq>_JJCJe-5H~4@m>Y$AT<73=oJ5L%Q?Vq+!%CjkYpocIX(05oC)=~NxJnQf!pV zOTpM3aBWy-<{(Q$uN1SSD=^ZU76$TVsIwFffD?NJU(|3OP@I(qt#M;Bb4bU%i(bnq zZ=_IB1<6>(h5UQU%)hnA2^Kp)BN7`HNJ|3<#w$h!?xt!HwoSX%1In+m7J<7X-AX`A zmronif6r{#9rA1L#tpO)2!KYdV&)r&R=6a}wBT=Ivp%6O8^y`hBDSJfNEt16ET}j1 z!BU$PjMAWsQ72nA#W-iq^}#}&J?FY)JX29*SGKbKt<02=){4FNy;=GCKz2MR-Uyc= zyK?o?%BE=%w4JxyoG&vwF!`Ig5T81T`U($WpJ(^7(bzm~+Mg|6uSFuUP4%isX=}lb_ISSz;4ZHqi5V$~^nv&}JBQit(-V4x5U>GJKHg+ty zEy~qBJX48fo19)nYT zi!5>w%K~)LcGm^fI%go-&P7y<>EoHmDh|aLIUx{fv9?R-wtBWv&vtY=K5K2<-zO=p zTrkoL**q-Gh0IiM(n-jigYhg?WU@!#Uku(N(r5;HA{rG&v-IQVq@MA_RGtldVnTSd z-jY%3A?25i8oCPq#ww|o%H8NriX1O(blvocu6DF3LN_eJ^rhKzl!bPoFiQdIHi22g zd?AdN(VFJtl@Q?24%>Bprw>yi*)Vd1)V`VE#u%JFN(WS48Y$T45#vyA9udmV#~zo* z9H(!IB(~D=FTsXFrb>b1uGAV9wMErJ;+7@mt-8I!oG za2;i|t4w!f*bQ&H7}cscatYzOR3jLKYV*dPsP^DP#uqu@VI02;6*$Fapw@2b6q7Bl zzrI~=uCyccG*W5`TJCtdKx69Kj-zJ`DSvx`MCD|4d?yj=q z3!fOVu0sSywjY~t#RI6_zMSYcG1uGK-+)(%@$=35`yh4AS9+W7Mgz$kz74BmUHF!v zvc&fyQgV#zgd6WcETb1k;~}>i>*PM&B7BmU-Ml8l$wM`;nlWE^($g3M@MN?_E~IK& zW-G~b`wrw6q&_HhslA6jDBO5Y+VlW}f0TWm(}k^{x?sb~p{Ki>d98VU&{x8FPCjLK z%-he}h5GJ!-ld`AWx6t@&|suB(StCMYlw9j^Dbtx=b3kkryf5895UexKSeH>fR(AE;?}qj1@@&xVR&UF)db9 zVkV1c@dga{J{N(vYnKr~F|%W<-Jo_man>P*y?{Y>G$ozka=^`6hqciiVS?FaiptO& zhkX-oec%zQFv-F`T9Vn252HcFkcI*6<9vmna=}mDNorV@wGOrb_8e7D4?wGGj&`%J zr)7LeedJ?NG6~o?H+z7q#nZZ#(RFzb=cRp!i;Eq1)02YF&uVYU!`M(`^TtPDHLTS3 zD62zlWm+e+0CV|{A5(^1J+~Ck5dr72JA~m%4pLEAukC*J9J<@y%p;UhLQD>jG?T~H z*ofW5RF;me!?BueFI`#df?^yP+_ZK+2Mek(4W+!1GWxUMi-9UyVgVF4dBds*uZbZ4M z(doaEnf0!fiiSm!mxC9;^Z-GLeb20sM&|3bc44=p$|L59oP`BStq9qOp?+J%XDJLZpjbro-EvOBw7u@&kRbjO61$ti$Df z&z@T+?xT!^?kQMcDN8%d%4)NABKgA(|nsd2PEvLs)r-u(h<+N`MIKwBQlagWuf>@Y_4Brc4s- z5JUi4hBn0q2+J`GcMnKJ`L_YAK9XqI;dWLz;S#No-6apU(am(Fohwx;{W;hZB~WKM zEiNqqMg}2)sYvwjJU`V#4}b@tPhj6Ar{V5{Bz9f~;z?Y)5YB2m0ZKnDtKwkh8x+(% zuw{2CfY~YcAlxN$G3~P3i_)ajL*|+HV6bx{F;-Po>0Mo4&kb7ho5ZX+9tT~j*at3$ zCZ$_iEx0Xn|0pX4%ta!Mx}hoisXn-Pigd;cjIW(sYP)m#dWBQ&6uaxFiJ4Zob|D4% z+JN6Y;d#y!tIA*lYVb1?R!xaErazJ7Tis?KO~hcb=rpvoS=TX^#SBW1WjSfH+u7V& zZw;53V$F@seoh9r=wqk@>Far11ts&kN0(}OIIS^TBiKD<()N@^Z)avRlXgtp(|om@ zYP2@A?b`$NhDawEwzhNZknjl7Di-Xk78&o~wsXZH?#y;erdWv?l zRp=ZpZMd6~YY8;Y^FvS@vMck4Y?352mn=(7>PWK+A}e^$rl(lxkeF3Cm?I@?*i7MD z>05A_%`W|HW%Ha)Fy}aD!ZQRxS)FOWS~{nX3}&8t{yAy7i0@%Zituz5F3*P*MVris zSvxr}j!4hy&F{h8SkKOBbjFT-$5^L1#x+VFcb$gAE;*>qY>-4tr=;=lstJWH<)*F7flkfQ2lVg7iM-?i5~NY8+hwj! zVWoCoyqY}NFNm7rPiQrzED|wbG}@@z)ulLADS+&T#OP(-%x`n$V>J3UK?4Tn1Yk-;T!R8Ses?mj=Nb3`=v z;Vdgk9<%xu8=1L@)`HAbVtFmB=6^9t_<+!xSy;LHLRj1%AB{NGq_nUG&^*}#&}7{M z2!nbk(5yP$XR~6KZs7EgSJOx82_aKg!2Dp3#bfu>)F;~!gO<4Vq_Q2BCHLt!ckH)vx~~1(M{-u63kcbo=6` zY|=)FC`Dh5A4i_;w5q$=T7wPhOuHPW`ZZOYKDwqQFpua3{rOk{5pSW;+YJD_5v?>q zH{|zD)-mklOrI;=I=|dEf8lhC05(AwE!n|h+o)*nQ373#81|P=*P9o6-*ct?_@8*c zzf@YMVe>D%M?f{dW9eiB?k0CD<G$=E1VQ?H)6^lm|m|Mu_U;UhI3UX|OX{ z*|eA}PL`V%WavZ!*HjKHGZa~+xLEm${hC~n?JGk}wA9R+2V^#z1un-Tw4?oUWh45u zcHjrK-A{~zUyPr&?y+xY3w695uGFiwGjiMA3k=6pjJxZnR~?u> z#;4zCuq67haOp?+vexD%UCd*R!PBOSW|7-W6KfsT2Mz7Rys-~?-nY1+L}I;oF+C>V z=uZ%CR6GtUp;abc`;D;I@0ycK*V2MmrB=4HhHInqWA#9s%LjLJ99pdQ(JbO61g^Hvo>{v#pige%P`r zQa@O0QL@0tESBB88sn%geNp4bZtPn(v|M2K>`ZY0h6?Bb7CKyeF6P=Tl)bbn36r6$ zbOR!l^BfZqFyWa&EbPUGhY!czda_$8ZRp!U6rN_YL5f_~hAXeswz&)fxa?*e+S@K= zRlCT-Qh4(vS;Tw0Y)Hc%(Hce)7>)o@|6)Hw+d(;y4hLs%IQ12`ZQ-h@V=GCY#$AFGQgXe|)At`h?|8V~PLp1b9uRBnSlPCUyRaaTZ#Y=EmJ}Aubj@r% zm)V-~3j=*F0JO6m!mfeZO4!O7vrO`nojGy!k1gEq3L2oxsdg?yQRqbFw%SHEVw-v_vkRVpNLUX}9 zzM9ecz5k%7^@AQjSEC|e_c&~aDPncmtfgSg%(xQRGI!2)fAq;mE!+Pffz5b{HE(h_4S7a-nh3Xz>0t=KwDiV7}Ld zC}&z=q(W>tUzj7P*&V;j3~&O3`vH3a>z&^Ca#LH@cA*y=-cHdI;%a=3Mri^IAU}`$ zszv9+hHOMiw}-wb1@+R?6g^l|2I^D1Nc}yCRUKyv&(wQ{uq{|2GT*uqf^Gnq@m&DL zKG6fk0K10iy?bFV*u*FufBofY%;b?AwC&T`jE#m51KM_$A0Snm68H9WF2=Q+x)KRi z+Wo5AX-rtB(JI{&71nKsBsBEpz1;z*XNM9xuODvN4Qf7ryEe>+cQnQ*i5J*4-N7VC zEz0FDPLtrK3babBsxDNyu*;Vyjk|geSYPW2y&I=#in7ni&OXz%P#7pK~Wz*@j7n`m-@6G9JBoh)}c z^h@l7%v@OtGdQs7d~LgYsorX58zCUtGv)gM?U--zIz69L8S)jkYp^T?UuR#oa}c%u zxtiN7>BTtCJ4xsCwE9vB+a+djWHg9FC2EIb6mVR;6Mt0(^SaJl`zl1j5Q?F>=&9kNtI*5 zP9+6isaG!6(Fh3~ z?C7XlCn?Dp zX`NGm&m@7mOcH=J6P(tt1KBpAbkwn^6lu4s`r>GZ3Dw0ghUAF( z6Z;wQDrTQn+^HN@QX!o>)oI0a+gPXzZB?aEx19Au-OXe0fjWlK(ecWVLvp1cdS-X~ ztX1t$M5&zLIh&KKeBPG7#2D}J4?!)Y+?h(V`(8*^!o;zzwf$KS9Y z8pN5FJLVmx2-jh{97kt9;_4}@I9k-gPN6<2Mvq&!KqfnLvTq|rS6~+LcFzS?Du|!E zLY_9gSP$|cjuxy`H!60sRpu6iweCLGTxDQf)5)SD&OTaTJ6Y3wdfpY(Os=$y3UwW{ zJ#cgO0Rq?2hr!kPCFHr3*flZHIqDF$16?6f^#ttApmBD@YB{vJY$i(I=z;1&13=AS z$!+8vyUH-nBr=wMT#7Z$v7u)tRC=;bd*p@AV{Uyq5w`vuNzz<-#u`Vaa>%pk1L-;H zKMXdj{hV+R3g?;7Smh;gMWA;G-=#(3f64CG>%Z&`8%~;ea48F z@nhTy8DkZ9|8_^8J=T{(U2dn`ZQQP#xC1LptYM4W2KyjXMKIAjFM1NS$2yG3s5TZP ze`s%)`2{2JDzl9=sn)T09>>6hqAIc!PLZ4|c6UkA z89G@dH+d5Qjco_Y-TN}?Dz$iXsH@F>*k&J%-d+9O26yaFF6}TlJCuXOR)OJWL0f|3 zu9ww9-`#_*w9KifQT>ALg38A)rw-s&QWr+NF?vk}QeIk07trA`ef(KKY)74v(0zQx z0d0xw!<+G^gV9jFkzBmbU<|Z_Z`c!5N)z+!-ROQj_sr!OAG#zHLE4_1gV2kkh)S=z zVrn+)4ee)Aa_F=@oyT~zZC!)VW0|U$DXMl?pmpXRK)6}22e_9eu}R6LMz&SAb&)6$ zIPuH@^+10mWuv_1xc?(``^Jd+ld} zNfe+4Rl95FT$XOqiYBBX6W%CCx#z93`N@6YeF+A1rIuM)ufQ=MZmIC&-}dzFLL(Pa z)w$8{;x_nQ&>!wa{8H+8wAaT=I}U#9$;lF*&8ssB7?a-G>|z|nZM7(?_c1oHA!HJi zp6UYep)RUtx)9&Jsa$YL!fIEjn(kv?hXUhd9`D*ZA=MqN)U_YKu5(nwo*GmT{fF>7 zvWMcj03)))$S&wbDi6^_tfkgRbt;$VcN)w+cA$h=MEW*Nw$#Hqo-13~G(lYYFT1jb zJG=~Qr(G%Nt`wEY#58z_(w8M1_3L06Ax&VtLo(~=``lf!PlU~87brI2mh{z7Q=#af z31_r`iQ4mq7KU#OQ98Yj?}TWH_YC1vlFy}$aI1(3;$)WsZFUSq{#emLZF9nSKb?Sa z1xli-T{Jf6N)jMpz^_Sizd&3iO= zRve66;*%Q>rE^H2us!ss;VSXlKd@EYCjlG+bYd)sX5zdDyG*Mno(@$D$Hcq zEJIyAk)Av4oywh zxq!3?q0o$NP~JY)HZM8pX_jR!3o|S0a9T`uSCis4jG1x)LE#!*WZ!T$dMSd+iq*P> zoW|INtw=7YTYfHa^GV>=?e2Qz;i#L`cgjMw+ zyt)m8ggs=4dj`}=u9;^%eXQ(%RYplK2%-5ofLzY8opB}-4g)YuS#BgRqpzwFJ!RSl z>AR#I(maqOWZ&#R8rqBSBvG_(aek)8`+gGGNx%>CL#u?6PG7tMdsQGnVo#Al_M1zgYA<%scu+LGZuKTEeT! zJW#_uN5CC>5|W8)GIAGYX%f>Tj!nh}CgSSW;BY>V3aRbv0>=PKcTbpgwEvtJK>KV_ zFN}ldTz1h5<7%&tFJaJqVI;s&3Ri>uuqtJ=Ti#ZhG9NHHz1=x@jy;#e2l>u{AmO;{ zD)$B|f_8RKK_!y(K~T(-5B3S9MrAec@k*6&A0Db6JqYz9g9FHeI5*$MDaGgGKXpQp zXo0)xwac!UNJ9S26i^YEd<=*!p9=_x93Lq|c*nzpzZ=OrWU$O#e0fYuuS6636{$@D z7Sjx1fm~l;(f^;lw}H{?I`2ErJHz43km8UtG^?m0t&tTi$w;I~$%-vmvQ3c`#hPE@ zj4U&fN>L<5F``JCq%0}6keMN=*l2>pNQ&5Kj7`u4+oCn#q6s!dEz|)TY_dqODX_-2 z*b18f4Yt8!@j(ln%cvC4rURbw#1?g^T*p+_(OU@3g{&(*|T6EV=m=+1&2xe-4Yx zIos;_{>zxdR)J^Eo1%TB11_j#9mIJ-`&^|XyxG-c6(_Lr=ca*?}q<%Ar+e26H&;dGM;=N{~Gf||NUZ&-*Ezv-rW9ziYK(Jj>!DWHeDp2Imx)&Jj`#8#~ z>y&Sgd1TEqC<0N7;6;r8iZU6#XW(A8o^jJ$Qc9ltnJXuo61`V$c-)-M**pf=c1gHs zO$D!jZEmD-Yu!^kRqkqAX7?Qozmu)>me_B~(I*b>GNKFiJxg z-r$H6HLGo8%@wb76On#Kg?xhG%qwSgd6ch`=pzwaOWhsC82OHO`8bB=fOyETtJ~Z% zmGguAS{_$kl;vCAsBRT=>4?Vs3NJsEO zd0YpVLg>Snq>s7<&7^h1#kr4s?n7qkW+dIpXE`FmPhus^;Y)jTL@n%d50#5dKU4k$c5W_~OIw3G_RP_kcx(=~B~@;zgp(TBP-7|jKnhkVI{y(js| zmwsm7ID0-{&Nh}mk0h?$w?MU5kZk}t+*0!7*-Mv&nW&ISmR*MCW6u_SshgK&W}6!n zcypP*Vh1F`Z&Rdo4Kv*vzSiE9UvjfrYppN=HLZY+t7frY*Edl?X4+C9HFudKI8yic zP5Jy%?q%=k>0QmiT@4+xb>y^koy27SCO?Slu1SspeH~CAtB*amd6`glgPP`;RP8Rw zZg`_zmMInvlgZY-;~7&bCv;vVR@p6Q713A9SuZ^mtr^RUe0E~?0*EbT#aYV`!)FYh zKH~ahQ?~c~7tU%nH$Sgfvqb&rvK-uVr}HT!RjEfn=Cqq1Py_(5?XuJ5F&Nd#PXQw7 z@kM_ErF^@zNnA-eKej|Q8T~vPapc6=ZoL_$KhB@Izj@0h^^>36-mJP0!&jweT9#mm zYK?h;PK-peTvASaY8hTeV)JS-pDCsKFjyaX?36EIWgaZu3jpfCJtaxo|kjV<+*H!)+hJ;j?-Q`ML z>-;^JX6MQoUl-InCR}p7d*WDge>u0uFnOuD@M&9Cocc!M}@Oy4xzk-bVnW7;9^GQbg%Y2l z!YllBB$EwtI;+pJ$S|ju^Iu+Te2V;LT$5BVvV8EW+}L=;E2w^nPZWhUsEVkyzZuSe z+KW8WbT>i!B2RNvr45Jrctopv&1kgl0Y@8Z_+Cyx$avy958y;Zt^;RDm5Z& zcPrN+wHQw`X{-B&`{Qxw(eC|~rk$L$%dJV~@|t6(H=M#JKbn1DLVxh=bHnfx>Yn;F!;%FHfaucV?Tnnr#bH7f)ua&I@$bI!maNK zD?^_lf%b$X`@hhjJYQ0p1E8ijt||Y5)XMoI%K3@{O5uGW%_^GC;?Hk5fm|yF(4mKE zpSE@JD`kFGCXUP8US1u+T~@bBv}EeZAZ-zZ&FarNFq% zZE^vS`_Jp6LCT@(92RQj$T}Wf&Yvf7uRK-H{Ai8J8#*KMl9s-mIxMBm@gEu%+t9kV zISMqBUC`OIm;9PCptEnXghWem^+%@SO;qu|W{GN^Y?OM@86UoUQpp=%<#prDrKZth zw~9-!p1xv4LXzEC7s0+gMg0zK)AHq>S21gTq|u(xxe2FEzo}FJe>GXCzx0=PC(0Am zCrdJC)c4)zGumBRKX2}>E3|!yMG}{;yxB~MH1_^UrC1aaYvoPuNSP*Z7g0O6w2!Jd z{4#fWW?e~ku5&uOxz4pNoNDSH(`4M~OWc8)Ll^XsVcy-v2y=tJ;-RnLdS7YRsoWV~ z=XG1H)CCXwgo?d*F zzccyt46Y0~SD0 zC0SuHE$AUO%g4Nhf)AiJ=&uS&h+h@%>V7db23$v9-LR?@F1k6Se0%l%wq(XZ!ty}O zJ>6UK_)27Gi!uUw{;l-vEBcnOew~9osBgKZeAoq>)%dswKiP4XwXoNli`nbU4*LPL3fUv9-$aGkGmH;w03YK2SYl7@I% zXyE(aSyJ^Ihs7;g!4JUFTdMB6R-lC8WrL8H1iL~M9X_Xgbzbz+E^iec;cOD&&{di= zSoi+;=h@;Iq}RN<4qwlx@p5rtQZp@a9aD1{WTxmie5dzWc3#^j8by_6k>0?!PrY>h z)WxU>^2=v=qqN?69%Zc^<57qeX=cZxh!*jbdWzxE0mb|Gyro6x`ow6xj=Ja7-rd~; znu#6LOE!bPSmND99yct~Kceu#`=4CtFKX>w4^&~3d&i0(Xnkf+F?g1(f9+yVxum4M zV>_De-MAg)IL|$8&~|r^a<^V|*!Lv1Rz}U2^Ja%^7g*ncEo(m3>6I_opBw?|t7Q4> zjC)zcBXi2%iX3iNW%5ImPxUql>7~~%TS|7H(A0po#>j_kE=Y>APLD#8<>ybwT~;ZV zeTMHBkR4e%RnmDx`54El$Thn)xSe6Hp6ak{_om0#g%}@Ve!E#YZi6BM%06mIakn_D z=l){P*|n=S;N-I=8VDkhlHq5E<>5=&iE7N3uUmS|McFkp>ZFPCj5?&~UYqPW!Jj#6 z_9qhm+x5lt#WbBR>fht~_rVdRQN zF<=anU{oJ@5vEP2)Jb>m&Q#Emsd{TVy`-np`uCc!3ud>cG<+hZ$+LQgxAiH2T%Oi% z%Xf8IXJk+MXiEC~U`nIY>4~&kzn3#KX(Zpx{iFSv%n%MB&Z)D{2;nd3?v%O&fY;NR z^r)_0SJ~sL(*vK^`-~1?&oQW*Zwj%YndE%M=wf0lPP#Ar8E8H0UfBbUMhoREgH!D0b&qc zB&E%3i}2IiheZ_Hw2VMZ+Oz6Cldt`x7t-mpMSKnsP$jQr($bC<1b?rHJx=RC*l4Hz z1&JR?{%>naYePaUk!j>5F<&}-OwhcpH;{(&`p>FoIo#flhs!CgF6t_+E?7xB532oh zVlR|B(gg$7BR`kf8>~}L8sLjJ`^I!Ss5Z3HDAV1yA$eiL)LwQtzM*R7ss;A>^ zGj3{S13lreQ~J+TD{X^8y9-uGjP<12yrlo^IGhvTP7Bko3kMf7wrxAq<2V*V-;fi} zz;jULl1hWm)97oee_lolrSn!wYv6pV&S||9ce>US*8v`$_)gdBccgnXx_hes(law^ z4efM7_6$n}wB`fU9rArSeO|Ef1fx5ho>6(f^+U?xnDgN8^_y>X5S2G)2>~mn6H@Y$ zpxCV6aI&z4z`H$lhPS28+|PV4UE6yEE&6TV5-yq8{$?wZ}E14rOiF*@ZeU^Ov;msqe1jd zwD-v1_MTTO=3e*_uCXPlH1OeG?P&Y_T7D0n3Vgt8Zp%(el(#i>=aJbw2JmWK8uA=k zwO9f)0Pc=kN_Xwg>}2NyuM^u9+EO-T_<1?5&nNvI-kdrko5g~iku9p1My8W2ncUg` zjywH+iQmay)}`KKs{Kixp6ner+8=9&-w38oikfIK`*qfnwax^$;KyF=K-@ksm@13X zVp}gv4g}7q7dv=ZEkp8XNJ#!EB9llw3t8X0@3hnzy(yeo+kQ7a z*Nb|G<~Vh@fi@I2p%|}F{<}4TJ?W_KQ7fm_hqFMaPK-r%&KeebAXuyknInv#F65n7 z_90qBP-|>BSn7fKjorC@>Jn_bH&ity+yOaCn=lQxA6M>(-oQ_pQSG0|w4I=z~MCZff39Ehxpd4VBUsj>4FT z)-tB^xxW-@uZ)EYboceQ&o9)g;3RUYYm7u8kx3wa#W zg5G?n_swW^iFfXsQR}z{?KTIFYG>44HXiyQx)B~UiU)c}@ucWPBBBjp@K2iihc^;1 zvVtT{gC&R@@v>p($R3ms<)jdTc$?i}_I3#@OB6u(68RE)izgIU!M>*ur42{YzO2Y+ zq&}XMsydMNDi(c8>~N5)wc7>38T~_@Y1nIbsrC`6$6XTEU3&kb;6Txx$-^gpR9t&| z{m%A=MPE*7?kh*tFa?H6>SJF{W_N$xI6qR~*h_0K5=2OM_r&t!Pv0Y*Xk0n)swzg*#DlTmzG zWtZ}t1=3CVObPYaW?IVywVP-nk>OXKYf1a-*aK{c{`4`dMI zj+`_Z0kYRtlBh!)UN{Y(`>g!d)B1;DJFMQ0=?dTqLg<4M-asLjcym^7JRmMRnz?IQ z95*XY+OKph?Sa~*p^K=t6-<~2 zkP6l$UWV<;`0KG*rg%0j>8RhZ`g>aMLttl5C@ZZwk}7c8biybYbVh<>LfisuB*+mI zMB!!K!477RLOocmO+iYOlX-T(TB&``LaR2jfrB%u3v6J|CJ~kemNOY!LBG3GI*ZV> zIm+z*vY5iM&HNQQ2t!ykaIxoc?{(#fM4$%Sou2Vb)>DgZ?jkXmE* zCh}wM<#I;4e3@OfhvzhfQ?$h%6jf!-4{lH(4uLv%wC8DFl6q+-%pTgMT4t0OL->-5 zLEf3W`b6gIqNHmnv^$Hs#)d-@%fRxu6bVD z)w_f%XhY90Vlb^u2De_glG#pV{*2ykG8n5LP9M{h_fDo#m9=VX6YRa+{%jmycz?1| zklu!q5o**QVCxnoLIg9UT0h(tuvy_AM@RLq{c!|g*x(F=}us8xIn3>|(E{R7f3?h(x7Aito0b>`R8 z@8H4#6FM+NVX&5W03V$L&MCcPy=?o2gxHF-H6jBiRQGcz+xg0wHEETM^WN-q?v{jd zzgtcWWn7P^XVX)tplfJ|zfRm!IOVt;|Duo1HX7+8(p(sxOX(w`{`=KRbq^PA z*h38)h7e-8HQe{#&jFD->RwtJ<7Ey%LW0YBHXZ4tX+5|KH0Y zOKpilA0a_?d9Pe!_|Wy%gkBLBeMRYZaVIi;qdxnsMsM$>MPJc7E+sw!t0tr8{+7c2 z)Nh1j-1x2YIh2~#%1U}+DNek5Nccg2-nb1M5OV*7T38L^!#=>#MQoVy=CM86SgNp5 zXi!E&0?S?l_}wRadRX4U5y8~9s!?k(-@<8wrTmbx|xB z$R{#Cb=JE7z)JcU3q>vnFX+Pay2AO#&VYZe9liv;0{XPx?py6PrjxtXTUkEk*#>9# zNYmI?4R16S4b&~fJWOD2I(;^4wf*`_a!9K;m1HdbM@V@()|&V7RiYj8Qk(%Q zN|d@5A|fJUO6N5Sh>rRCi2x|PQ?G@K7V9vWjN8-MC3YLciS%PX-d;RV49=j{?`&7C zcAAy3mOLW8Gg8_%bgZY15PdLgjFX86;%J0FCUICvrh^gG&ZEk9J)m|7dR`H0y(E{} zvB(2T<(Boky>~!DJOjgT)jMha3!9YTA~Cel?eaQ<(@Nh?1;ohSQqVEeoLw`$X)_>`ZV+o>A*v< zq)TEI?Vu3@1$a9xERsYsiW}EjquCm!+uLx?HoibQO)jc`WRVrcDz`uS6!q7ioArQx7ZB)_8h0GM;`|f3u!@j!`Wq#{s0!CdN}zK0t#w zpH&SwoB8XU_IbQkTt`)k(sXUOW|!JyG2=<8G&uQ`G6i6Uc_hs{ul}@X?wO-B{^__n zOfs3}PfmFN4+-~3VURrpGN*~_{`crDxNleMeXlnt?WKFMcJP?f{-?5(= zs%xQV`s)p%WiMYCT8sw%M7q0fbztAmJY7Nef%SXeVd0c<25%wJy?n70=(R&auJS$O;&69MGN*w z((Zm}JnI!}pOEABJF$`q$2Uvr-W#`pwYGJAMWaBM)Bk13G85amm2HFdxSjs6^P$z# z1A}Y#&K!2@=V=*iT6+~-_{dA!!N6u&hMhLSQN8UQ5*@*9+RRcHmb1jN7UY$=gT3Ow zSy^%NJ2TpZM-BpRIhy0r>dAfa=1k5k9MyY!Rp*dAL-_8X+K$?3ebk**M*m1|G2Q8w z$@G6#C41z}IQOq!yY-(?EBKx&o19S(%xbvhUD^r){7+<<^?a>I@Qj{k$X9<>(Ck&K zdbawR+{#g|*8(Fm44-qm+GZH{JuS$CH5M5Ct~|C`TF?R_umK!LHJ;C?ontC}M(ylZ zu=$McU8cIX8yjF|pPqNiMPEfGjsLpa!_aNpap_#zgGlsB_C z@W5xp7xhlu;OKtKp6jp0?=1Dxo$xze*(pICJ^=yxwDuA{rDy1Yw5fMYp;dF6<405v z3y>zm{|so;WZ1coh%|Xb+)S7oyN64ObG+j7yLL&dMg&=ORToQZYEL3x)}7v2ZHiw>OBU+6%Lh*zE_`%7jU4fYeNhkuvW&SXt;Fu$k!ZL{jbdYv9GWzDD0 zo#tzFS+T*Y{qSxGPPInkz?iu}uKZNwBJAeb~ZWsUJzlZirbAJqZ zFlMZ6WB9m+fM~Z6HSLutIDlRuAgC0PdEmIa&(M~;AIip#jq%%Y0bKC&*2;) z86gS_6>dHYQim`P2$3ZV@_aP_2hw%rVLX&bukiuy$j%&L7aCbXjH)7YEq z+T;<4Y0k^`QlBNcXm9Dak0EHpMZ2;HI3I;B3p--pu@CX<``=4<%t|d?l%4HuG3{OK zNf2yV#J>ARt)zpC)hL)YBQLAJt;=mKZL;DyC6DNJ37PY?p*qrC&q}DE+v&m2wUZP3 z@v5Hdyiolm&a_89usy{ZmXMJf(pOA&XB^NrgQijgDIUhE!9R+mSIra zR)1JQNBo$qUg<(s9EW%@w>eqaw5`i+Gu>r7YgPYpmN(l}jK^hp4~NtP7=_ob$m=_= zI*}nrn-AzIIl5W>^&)jkEPj#WBHm1*Pwgk5LCDl1i$uwo4rH?HVKmVPvV=bc?-hNa zLw)kQr`4-ttu*&XF+D){y&5_6c2pmns4Ibx_nzY((LL$j{ypKnvnimbw)&p=ctg(J z8}bb5xsL6EkU;YRp$#T{AS;&eSe#mUK$d>HRN?mQMZ6{i$+>9{5!{hSbesoY(iqqV z@6OZrXTyo`Bd`0{bC~~o4D$&QxlHr~?QAs}!r#Qf{ckZi>k;G#=?UFucKe$#upKSt zd@lxOb;9%o${Mwb4<6Gee{<;88s09{+p8_HLd+s?t9N14`)JCp2h?nP^9p{j)wM%M zJ3La|TFi|)1a~^sIRBm$n{)%VyV?J3%KcGCW-kQ|P?P#(HB3Zmi3koA2V8rJH(WML%UL=zyOat*3t$RE}j+>+qczA~( z0oK{{V}c~)_s4QgxlL74%loEC?9hkJ9Wg>#Hcz5GCeK)W84dzrH3^oZ!oe5*L;12Tc>17lXvP6h%|v05>$(7bsfaA(~|j8yjAyADtS zBdvIHtR&;xZMXYvrf5F(q}s#`BdgJS`@JarqUz8G2A;OAFt)j`?-xj{+a2t^?#~tN z0T4rk6+$`KuG2A@)x}x}6!iN*?KVITN`_+^@(kPjzpi6yUdJ&vkHHO$0Gb;7-J;xd zb|XEN4R!6%+idoG0_F#255WGkQg+}4+x|x81qQWPyMSsJ5(>f<03BRuod8ALGV(?$ z#Xbp(n#@nMf>baPPiuKUOSojTz)Et~v$%!D5lvt96p!6Y^8%zIL5>EX%`<}af_jFe z#y~8uiC(}q$tW-qd${Z;MGe}5?+7YP3wuR*LBi+vseML;gUu0Q;# z3oq!ctX)AeXk&3Ipn)w%oqI6FC3s+z^bKVw&AR%Goonya@ROng;V}ARnMHYfkPk_i z+uK`#M0uWkQimsGz)*0janD`RmKm-^&Rc;##g8(4J#XII_O%YS+TNW`&7!?mOV^hcE3OMELf| zZ`j5g{WQfpvd07af?u>-XaG~RSGR;#?Oz~=B|)dbc(z?<vS|uM<0Z)ie^_P~daz{hxJH7; za&n4ID5$C}N|36Jd-3p@Mr7h{PctS@*bxB$qiX5w$aXE@I4G`8hoP#iAuZbTpncPF zagHww^pG%A1(Zvhz>`OQI73BGfs1t4-Yn(C|AyAZ2E^=wJqD~9{6qq;?RlkpA{h!U z!W-j=892zkNczbq^Ob!HBppueRerS$aEjuM_$<7xewc{sTK&)cew+?s#1@3%9x%9Y z-63@-u|dvcab-B(;edu>s}rsuJ~AYP0Jk#1R41bPCzu}28%R5^E?4~9P6!CYjV6;v z$Q0t=R=lz9!741x{mKurvszZ&#Kce6d4{^5TW)bLnwH1} zJ$37?>{BcHG+pE6T+Y@ZqLjfdY>CQ3Fw;J_0&iIpzIJQvJiSXJ0lU#k&=0D+%%?%b zLZPw+qqx*j5BjIQhKxl6NZT!rZ)@bUBEAk6-%~V^g;B;vXS+t`YeteoR7cc0tAC!* zz|s@<_}qy@Q9CafiPFP@)UG+>Zoko;#Jc-XZi7)0O*#ck?g$?->xw(tHGqfq6njnX zS1odgXPYJQX*DI-MvY+;p$D=uqkpj+qYLR>@pQLpp<9rwGxAfKad+PyIL_|V8av&0 z?~Jw!zPiu4i(n%An{MBwzUf`x1``J}TJF;wp1!~nBAs(d*f*!9^^B6Y$X-|*aI*Sk zc^WKfgmZ{x8~knHNxh63Q^aWqwBboMwARV|9>$A|gWI!S`fTpK+g`@{QyD7Yk~UvM zTL&_=w0I`>cT`XC;|}Y2&H?W19nDNOht42E`8}!+9lE1z&igJUT^#1~E6d>*XVp7? z6xtB~r^};zYueqiZkaixkwyIGtr*}O-RYhOt(ifhZ1W-y;Ay*tS~;H#PdbCr9rI^q zL>n{*^0vK;lkM^(y}$s8p!}sQDI7x=+!0*v7MWh$n>O7S1y1GD6wTeMI~v>4N56XWg2zyABJnKi=)Bj_vVI(q#0GuyQl2zPa2Mxsz`6AiJKLlHon(P?ad3iEPVk1hEu#~e%xih<`$NUi{61?0K4?^wmID=VEYzg8;v+9U z(7FZAonE{qVqIERp7b6{y!-}*2VWwMW$r=xcJ3cjsSacY%~^-z(@xeGc7*D|;>Er1 zH(u?vE#@mo2T%_7Nf;tn!LLl-cC?!j2hyg1AyQXD@X%)cmY@JPGp2Zarfdz1C8VP@ z)BSCwJL-0s1x>fQli6zzy)!AqljTDs>{KO0eA7 z-)7gX*j10Q;KE}tZfln5A5HqAU4{NWu$#Rapq@fyYMU_Yd_x&0Ymo8!MBmUI14p(R z+(KF0clyF$q-O({Q8H-He2v4vAbo{`$QJ%Wxf%LEB*g0`oZHND%wZXcZnL+2Yw-y6@f* zBKp&Uu>UBS8;!!4z*O+1AQ%(6uVg$rp5-i!gFleD%?0k-{=oB}MD?l`HxT%pR( z2%mxVq)4gMt;+9cmlvv}`9Fe-f^WUEJxunNe3D3<$kVRZ4&#nDY*XemoyCSnu`Pqa z^~p}re*7XG7rR3W(zXW>10LK0AB(~1ICq0q3K}>eCi;)j*JbhSMx+n825Xcb7fjYF zH)_YwBi+Q5cq!;2#zhM-ChTKO4ITwTaYZ)mV%{YdK|b07#&KFI&ch2vN_W)HYK*51 z^^+K7yEMY5H2(&uYipMJ^)@@87wV^Vx4qAz*PWHY*!7XiH&x z92^qY(FVYhWfZCNmfFZKR@&fhoZgaaWQATVwQjOt&DKfhD-muMSuyd?(HiM?TpikT z?k(6Utq&cF-fpsQJ41JSP60!7Tx`kC86sqQV9g(z+ga_jZO|LcX5yr=p0QQ?9-tsF zw1M?ekr-iMY)13Ijq9)`k+jBH!Ikdptq=VW5;-LIdW=BgX}N(t-Zy9rcI^9vZtGHY zYtBjcE>$yRBi$1YFG|-K=<9RgPk+$jX&{1u0yqTsM$AW@_S_?PC3^My1ZI7iw=6DFey)$!=}_*ilzD$^-{HKR=rWn zK^@m~#I!iO)^6N#l;QRk|40#PCp0l5lZH4?r2kmXc3iwz);6U(%vCG|32teoZ|0Bv zWmvSu00T*jfp#kvk1V*6!P|@3yPBLoK%1qF>FCA0QD}X5&P9CFhEi7f$aDXwt-o9; zxXSr#bb*^L&4Egnmd5&P*UySOG1y3#;3axXYunJU-=0hjv2>2tHsAyLzCf0)Z@qN~ zyY@ADg%%oz`^s!cuX}A5y>6kVeA~h1YoUbGwPW4?evqO4F5i$C{O%xh0QDe8{6<7z z&L4bUVD3l9!vFT zMrI8dOEdA1JW)hKgBa9dMcoQv#R;_#nW%~|Cw@AQd4ZL`|j+^R`})G5qV~TWY z31XGhTZ_P1^h_@vFOhziA6y^NH8}Z@*7s|>w7#?)bWQ6E)w*T*L<6hno|x*|^}kiq z#cH)xd`*1MnS^a^`}2Y3#gu$7bgx1jB=%9asO3=FgOyv&g0(tbs_hyMjEY;XTf(;2 zt%V8+m9kXpp=y6{$~kZpc<)t#F`ixnUDtEIDTM!TRUk(3uTTZ9@0Ydo&cCTuQ`n{D z=*ke&k0>*SJ@j!`ao|&LzMdoKqjmPG_UqXjwO420dRyZoAE*nK7_^nhV$j9D&AO$V z8+FOx-Ds>=mK<%}&QfFSw?YMDbsK|5wip)TV6hqtP^aM2X%u2Da$UCQrC(P3AJ=pi z^Bqh|ap0Ga7F%A6o|1Jm@R6Le+^@_i2YR!w;aE@G9C!AS%thhl-*|S&T!DWB{3v|9 zB##k(q{LHQ#qYmytHEWpvNKnQqHkkyP<@o6->DVkt-(_p8`@-yR?uxYdd-dNzW@FQ zjn8f4jTT7ydAP=4V8rrbGq^a7JkeBZFP2%f51C^H3dhWmV-GGHtgUKEpq-1Ycg#hR zpZd`7!uSQ?fI*z{j%ipqPs&X(>vd6Gv>`0xLvhwE@fBLcIue367Th)~mx(=EDW*Fjj6t+yj)B^P&0)M5 z_^FLZF*v>HnSO36@7=hs+Qb&~3LPU}!+e!KYEv7Es8D@SisHsFd=ODzz|zkLz#mDM zGLAasGME~-W{3w-y>JRS_qGvs{ZRWKlmT826t(faH7J%gyvu>1Ho9#X;F=$d!7V%x zSf{VxpFvvwykz11Cm}oQOV1(U@il<9X4zfoI~h!!t&D`6P*B1;J)d8{U-rmr6VY2S zxy?Ds%&VZ?ScMy3h2RjISbx|5EIm}OPHpd8=v~{lUD+KUp!P2T(;FjV3odK0SUJ#M zA-%i?W1mbJV!dA4^BCTg!CnUhsRp`iFM*9%>f;^pz``0cP8@wJbw(Y5@fCOCNn$Z3 z&+7Xh<6iYR2HL;JG-+BsGnYnK>%tSF+O&b+W7-k!BeZ=mcDi%%{qSkc6FDOEanWh~ z31u1hKxfis0@_mV&DE^>_3E768fzSBeL%I?8J^bQ@gLAGHjcPXci8{mt$X5CpJm1P z*ge;u$KY*hHEpRMJ_*Jq>2z1SjovH(J=J{>CpWG1J)uoj4RUC5`<*%?(BC4laz1@Z zCp5I*izj4dIH5}W@cVj=Gpy3u_Q?Zj!=Q*hjZ>OwsU3DcX@H4!4n9vKdo+SH9v|RK zqu^D1p@X77ry6_JKUCs$1AkG3J ze4-5=r1kQ-wzTFcm2#B%A*~f<&mw0d5DTUe%Glq>vEy~Ffm(<3A9)NvhkH2u+=siT zah~(R0NN1!wI^>zB@HCw@!7w$HaHK+4u~J2tUpnfp&5_$p-EQ_RI9lXzg za|%R5-%b5x6=l~VqqCUQ;#B2CR2^*DN7H74VV5g!33I+K~}-GV!hRrmFw?`Z?{bgszf$H7r)J*9>ps+eZH zw@=(5_}0`D_vsGqkU*cQaa@p5B6xIQxUmQfx*z9|{VX5r2k4&FC2N+(iw~3;XKQNH?gR6i`jdShr(0{Rp~rwXje8Y^Fu%I2r$}p_%{?Md z&*nOCsbpmCE4yU9yyt-RC$WnFKhvg!$=TjTc`+f_-q+w2R+s{IAh3iazHd%6(B3FU z1i(T&n;m*eYaY`*NuAUBhGTl+3H|b^H4NRr}p2VUicjSr&{FAY@5S_z&8gX?{8pK>;UnhcrtjyI>O}f!F9vmimia) z8P9mXsdW-+`@f#oJ*r9`|5L=SX* zZI=T`;N(*}I0g>2&qxiZ2_L{+vFVIu0Fip$t|M*s%ClPPkd^knlaLd8j$lB0c2>Wt zK7jv9N?$D3?jLB%Ua63vBcd9Dh(mQ*>%jO{T%@@N&^ ztHXFgZP|0&)^)a>+xPrItO75!+KO0urUBuRII~!6ynXmd#Z=r z9Af{${%3gih!Uh4&~i&dTyxY13(0a@GsI|b9GbS0e~at#gId{dWCgw2D^oi^b$h{^ z@$^hqT9QTq zn_ky8lq7WJpkN=h87k*yJg}fodoOJfkV4h>&v(XUaR>+=I88Bp&0FO{V_^`?=0q>B zh>@0hq0DO+2x>wLHXw#{@#Qu|7kTRCj4~Pwu*U-f(~7?zjRETS@%eQ8X_X^e+Zy#? z{-|ktqmi{`tXJg?mNZ5%onw;PISbfhA^cxHr`O{ycn(dtl%{FZw`inWrEg$|xgEA{ zLctG$q9w`6xkAS>zrbgo$PNo5MM8QbMVuojOQc@3k5AzscLCqoO+^r=Pi#fe^S-h~VJ{oCKpVs2c&!_n(# z_&zXWr>fnX<*=;C?H`wM*xmqR7tT+Li_ykt57lpkT=pZ(5T?68RlMUvyqy3*7hTeX4)CPWruN)dX8IDAODUZ?`ACYI z8O{l%{@@ zB3&D@;C10?()R_?Y3~2HS@aZSpz)bKDLfY)*GR1SAkg`sK41eCYlJey!6zt!9M6|{ zwE`A`OgRJnjQE{!COkGK$BG3}#{4Jy#}~X)>ecXmz(hZLt3+qkX%M7~5_^5rE^?bz zKdg`1?a2T6dS`Y0V0G#1>PZ;hwL!_*f< zn%HFDJlxB?mp7{uwI0$xytuS}R#)Cu&@IcKhQ)`f7sPg-YVzMpR+v5qZnd(O*)yg* zn)^-o@o^yW@diuXqdo4S7WnZDQ)~q+$8%hk2IYv3H1|Iq6nJmSa{3hCBY7x3e9rpG z`i4_t>2NwdCH@nPO^`IvlIUu@GLex?OiigmO>Y z;qrn=CKG)sJNqnA0JP0C6@&)$68Y0lW`ubCGqW$K3qnzU<$zxt=wK8`0ZL-Bt31Ie zj&pWB&&8cZ(*R)Qb2LCg6Q}OgI3Kr*wE$=7CW3V)d4V0`X{1t=AZ!_5Suc_pus-iDy{T7Fa$xTkYc^PI;vAt;Kl&i=^82=JUVJ1StxsYlhF7?Ng&Ge03zAJgJ7{LN{gom< z+r3`ZI%ORXYQZDtG%vCyy|3;hgpAdDcmG`T(Q{Va@LN$bI<6y!Q=>;GXkvZ z&^52>pLhD#k}lmh_lp4QZCz!qJye@>DdBfnC=sc*8ZiyeDh3x6w6BKcIVVuPmINo2 zJAgvjp-9};AnM#4y?gr~)M96I|0xkI~0ds^vH+!t6af=a3vqPEX_E~oRF+!2sksbS4)^Ym5&ahzBLGkFRNHtNj% z)UjN_gTbcaB-mctZHAX@9ZXJhm7OEH3ReMZj8z9&VY3-XalUDpk3Le%K0v%HPRu81 z+e2s%*JTkm4N66t+iQen+x4kIa!BxD23$H6U{2#71TFZC)KLMA!9s_DrV^)w=mKca zVi1_lgx6pO$_kAJ0hQ@AuN9Z1nqAca2wzY+xTy_|tSu$T?*Fjd`qd*0bglJHAV3+?Z=(n6eLZI}rWfdu7^XBVDO@&3ds_x2Jd zLYaC5`fL$QP4~DA0A;OHgKS1G>xbIZ`GF5)?!9)056K_pJRI=ynlKOnY@3}*y0mxs z79MWDUsZ>zmR`O~>?8_wi=d)D1RPq0`rj^Vb3r0tN^|h&1A>#XGI`+RNJCekKDGF9 z?yJ3oT3Tw*r8uh$+pcPR;HK95lB2o*2e`}F%&~<57Eclkl9$CKqomtk&dMS-TSRal z0a_>k^L{PEADFDn{V#_!U_Q)>2qMD7z$b+Q7J8ec;WjY%K^X66DZmRiKSZ`><+cj% zf4^Tcv0KO~up-7*1O0DyK0nxF>6P?y_IG$31PbB9zyj@{v#lEtiU>DZL_O&EP${C< z4hmj`)eu{_7y%`Nba}0yA|*)Ji<5>|R2VTZfJ~qSWssihXNq1%gMu%sHJj@4E`mv( zpZPkj9rBeNL)x`#Sr8*GHaezH=^;H1^iDyBv93o(uZ6DV{6G65>BMfmiy!LrDCz@z zFdmCVSwCuF;mKeOV>);zdTb6#o%@PIh?)e%mmnUtVEs;;2`ID5F;f!ym=ue%dU4Lm z($nJfeo;A(w^Qe>4-S&HpxG5!yyrA`^@HnryE0S$;AYY4%Njn86~WwM4%MwvWe`9& z#K<$nOAP02`95M1*LE7XQ+&sM4OTN?O}_XHecP)aq>sY_T9U(`cP`sbc+H?4eRv8s z_iBFL374y`RYOu7j6&ItzT$vhQ|2>&fEx)ttP{+uR3Vi6cpYw1L-;W3@WBt<5B zwTIUoEG5(EW1a^@>FMyhi{_{I7+cX2@rL(p6me&iP78rEWnjmdgJc3Q-Pc~P66U%D z-HzyZFMVQ{#x^+jULdpgNrYBDk|hV}K0>8vJtE~rc3rHg>!$mj>rOK*M#aZtT4z0< z%Pn6Fx=gxk11U9jugq%XSi)R7{6b1^)a?~~_hT>ckG|#on!}*4bM0W6QL}qK`g$t! zW2oK7g!50O&L;TF{z-o>DLqv4Fc}4V^}TkahPNYnnhVk+H~+TZ>^xV$8SXaLIAX%W zU4ak3xfEocZtJXVE4p+$W(eDijiq1P=d{LBg;kgIZT+mCc*Q$1aav9|JiSj>SLD%^ z7T6L9hhhu$-m^D9lA_+)khZYA);$MpWn$`%Ec%Z2aqkA{=wdX2V1o@i^>)gBl7|k^ zU>e)k+M0AmaZX>>qza7kmg=0;wxMSmmOQP6igsjbbnRCy$FVpyn(CQKV$jID32qOc{tx_0D%vn(4JA*oyb6!#{Pz|!8KB3Q`aEHO;hT0dz%=rzu`=9aP z!bzpv9OKj*{Ov)p^o4z$`&GgR*skP>#^^g|r{@0A;sYyTHS?Bdy1eq3X#Q625-YXz zfL#xZc?$!b`KbmB^t2p&$BtbMyu^+!2uCO`B0C`N|pZFo-EO}&yiBcE|OXgdf+*r z^!PeUf1tic46ua2Y&%?YhB0ck|^b1PzGw9A{tS1(o z`u#CdS5NO;45>gyudM8=bx3FK>$k$P7%{SmH)2^N$sfbI1%~~}U~?;vqHGoyr5Y}j z5Q8P7+CO&#{8%vhu)=2Qh|g#7Ms|tkezsp=tl4^}U+UE_kwGbCtTo^yBveH?IX?zh zm~xArZ&zLH0@H;@@@h;{hVb218Lzu$H5Rj2Eb(II&{Bd0WmGUx?Nq~V^~t|Z!u1Xz z6wfI!9(W_~yhT97avf~+)(l#htdr^m$%eJ8gS{NX7!9onByAn-KnL--lvib0(?f-L zrwtpT)6OtMAFvSV6i!umTCjC)AB>;Q9W`zWA2H|pr(RE8t1`3dts$+p>3*U=b-;-_i{k%w2>uWKhK558n!O>F!Xd5sV@MHH_&n z@Zt8MA6&b4F4yYX&lv&Em@QX-P~fy!-5zg*2SH0nk0olr+v_)H8Lc7gD4grna!I>_ zZyoC1u$0*s#vch#q)*}T3x~4(FA3z@`i4EVQ9?d}nP0plYnd6ff_&rr^3`a}jL#C3 zw>|fZA&_B;iE(O=nB_Vs8nYM+c`bb?Y}7Iyb1mv#ZGe{=cGh4FW*l@URu*EGfywE6 zws+XX>xWb;h#2rfv3N zq!FgCP8$`wTL;F|Y9qL65Gm8-WkK)l>GsgmW#T+O4&v->@idS-JpDLC0hN4E?BwKv z11y3tphDkq#WKi`W*EX52WoRUyBnX>l0{;Ly?O@|4nx77d;k~O;U3n3S=-}{fR3q) zZ8=EvL|A9@e%*nCGkIL){prRkp7PhIU#RJC$FW4-K!{ATtN{$ff&i`x!vm4E(H`|h zy;;=$9*G6QhI}A znEkVQ3MUjEUMO#pi7?N`sG?^_oQwfU4E~F;4TfLP-HBw-GUK!N>Tj?sK{WUCdjvG! zf(49iI=_QV#W?{0`f;rAN)3)ZO$;N#LPH^PZWuuP7AuG!l)#`9!+pkl#UjF@Ed%(P zFrByCgy}akZS4!`Y&VRS!H57};M=KDGVNo>(}&{1^tiw&JLumfXS_5)arW?yYdVlolF= zlIx|=gX!;gDdemHwS&>x_-&Yc{exolhxPBl^oaiMOj={T=I^KH)YA6!Lb@-d;U88$ z{Y|y9P5*U<|GriUKd-$dX?4`mwT_(P=rOI^zH_JEWAVdIaf+|#;X$cc4z!|{7YnCt zlK{J|eWM zH!OL>2|JBu^wgzgQw{pA>>@^IK=|@qC`w?*q9aO)YvK--GD1ghhK{$GXpMlfeQ2%p z(><b?!?QZX~5X=D#1&?w3 zUGJGShJ{7p%tkB+e>fuNG*Y1og1# zywa762SrgLKPLH))V z4MlO5!@}$S+umRJV9|S>&Lgj4b;4&vG2))kxRDFco_1i&PDNc&%uMQ$Nd%{amkV?4 zGL-TC)x!L@Zi|gaa6_2Qzja&8p?~YP)J|MD95&+Ug!b_^)-!v00*AjrZj08H;<6}B zHuzyzr^NI~5K=96t+BHRIvIvTVeB{7!BFVgxV=F2! z!V8Z0KOox@tvLUd?&zJuo6YG_&Z&qiPyMIK*=~5zlxPOE1Sh+MBQGuSs+!YsyBRZ+ zYL_(fJ^CecWSo9BQ-aJ=8h%c>=@+2p-1XTUvp7}G0!IumD-GKzehAgOwA)1TqD&K$ zSdJ+WvZn1N)n0TSXIX$Y2!A4n@aF~UYbt?3E{Xia#oL8^*d~oUr+7QPi%pwE$SD(!L_CLBkGxb!zjmw+zAKlz-LDeD+ma0V{EV9ipK?}vp(7s862O?6_jE*(rI){G*xdH${i2^*9eqw)N(8~` zCxo$mIR}%DlSY_T-NjCFVM>5+OOvh}w5NC(6y}$x(4Z(GH^j8lHInhwg5FPPB(# zSlvVrgAA$sHQqyOl-2G&KZy*cXFt8Z#5S7~fatAXI}|I)8ItG@YX#gYmPlOI{An7= zd_R(3!@)d*rv?W9PMYe=MxPfh~&(KG5FYYWIeHgtk!CbVC3BK*l-p1*rB$yMOE| zUsa}mFCclpz0+2|4eG2V7`LuKoB4}$=qaR)`)8!#wscmzPx(r){htHBHe=YKhTC_qLtFz!gdO3qenfpH@l)#biKVOMqdJ4ts3LH3~ zY`o-+QZGX!D@gY!Cr5{vJJ=kR0(x!oaRg{_M&;g`uqC?*pv_9GUe4(ZA1%$QK8nMu zXqgQkw3VctvNCyyFUU<)9 zW)rd4p8rd&WuzcIOdT8#hqH$7t&AduT1@I>sM?w7g&0>gruh*K#LJ7!SvyR!s|`!PTa=z|qnVI4_A43#OCkQS zLcLy>BF+8OUoBr9l)v>bvMmpIMz(9eKn!(es}w8L!>fs{fBS__t5AEcAON!42xAvO zDFi_i(N-W|3E5%s@!UUS3&xpTfg^5djG!L5#F%YggpD~j;IeqJrn?QPH_(}7IVg)= zF>MN2vjq2q=TIn3n@*gfTf9Ubeogm2B{<)GV!{4M7nMI~v@?Q_QSuccap&AW_REU_P3I+i zW_TdQq7`qpS#YtIiVeVcI>jBE8p7@vaRjhugj)K}8z>%*op7Lo|>0>h* zs1t$au9_$&)IgFbaB!-xuG1!IXgL!ieF}YL0S$+r5m}7mo|rX9^noSjle|HQT4CwKP8Tegwy~sI?Pa?vSS&X2UlyFd^%rQKJ1oM15> z1{bxTS=S7PF7=CO6fCrR0uK0#(a2Ujs~a>cKw1sOz>HwZP()@47zu5TVJm7CFgz^R z3T0?rjUFm}P|rChl%Po>Wth=Z>ZQF58>k8swdakjfd~fMdz=|sxQc00Kk|UYd3_zu z(#B;8Igmpn2mY8=So@&_&YRAAMYKC&gZaX1 zxKB&{{U}o>lf9*BP7A+ajsyA&(?Z_AQi|Pa5a9v@5I%uk8GIey1GD!&OP@mA8T>Z= zvr6MFXBsIfla##?1?o@-^w!p#Ah1S8p`Te7MkXZg@5p+{@56>QUDyHikoLJ4$oNHO zf^h)k>$}t}lHlmsJNlgapgB|>BoB4T1TT!?j`)Q~VG>4foB*_0tFA|>`L(Dk*tWD( zOQI~YR7n9fZS9o+R19op)lr6&=I=eMW?vRiuo**h{M5#=k1Phj@N^6eQ*YM8wS>T= z)FtS{r9+3?1lJnN7Lj9;(MlHjnj+Ckn?2kwDU&jd=Dta6c~2N4z!eBGL`!fD?n*Br z8N(&9GB5+76(1JJL=t*+_7>$ZDhz;zh(6jFVY~>cCZ^`^>7_z1-`E_7T1LghAPh!y z2l9LdkF%lW42$go=Gn|o=mmf*2KNa8K@yGcKG4GU>{Z*jLCgBncDpoWhK@j>SK~Za zc-e%D9nZH0XPj1L256I8BDF1GMkavCrWqXqA_?#cA?$bnZGA9E?e8)ZO$G^v%PrM% zlGfTZN7jnj@aAaDwZT$eGAk>wOCSXIMz!|wAt1z-+`5D~u-BQ5X5l^Ls~E}lVIiQt z_dD^OxvNJr7GNis*|6R`5I8I4Bh@zvgl6UGH;z~gDAL?l_GEU$cSI)Q!OepgP1kMQ z6rPShBM9mc!mt#G!giOEB0^#BV`X2|A*awBoHQPuYSK}eu%%j6E7IUm#BP%R*s``N)w4|X@gEkRC#(+kS5I{*hl(EyOA*PY=l>z^mo z!WGSiI7`Eu)a{(8;XxnakmAnROmM2#emTlpa$HrD&aK9(3>cet9Wci`I~9xF(rHqE zPfCoBjy$1e%YeD^fK6$X7hpQxC~6H~%tOIDD2fFhK!))h`c9M5*AUS0?TM8_`&jf~ z&%x@Zki@jcR{02*-3>(f7E{x|_6e#Z7rTbti?5-oGU}yIa{5OF7 z?StYan6S5n<%}B|)!t}CX7mdOFb_lA)tkwS`Jr@pOCBK{vAuf*_n{bLjY}+kr9CfL zjJkI9%6gwPd|aVY@V^hHHK(Uhd(z719LR*SH#o?_wq!5nrQtvwY#77ww)filt)1B= zLYv@C_CF_TV88yhyz_oqN))oX1yA(loc|ic4yXGS4VY5^G)FkB-T!Bgs=O9LyMUg6 zV}hn+9~@l#xY!%v{DS@kTDD{njhsUG8O4=E)!uAR5d7wQ+L04%?;aA^b<(PxjKxxv zHH_ThHU+1lnPOm}FVI_|)$j(9!tjUTO1Hp(2O|#T*ER?VbyOBpx=7;7YUgfculq@Y zOV_Upmd$t8^l@#^V{7-O3I*SCVKP!rKiQLTTesMgY(#%1H*h(`pNV{b zZ~psC{(Cn6eQR{X)ZEuQlh5<}jpp~)nqQT_*p%mAmA|+;*WWOCuCqSzOl4O_r-#PY zr}b$>zZ*9;EnaEfyfQMKrsn>1Om+XPGkN_nF4S=M;>-WBDVh7_xcJq$_$P7k&vh|B z-kHpG=GQbAG+5sHR#g7=xcJSu_;y@;XQgm4HTT{8Gyga!*fb%WZ3IU^zOZd*Vxz{R z(XH>?rcT#%HcT$;RH1IvUvr~ZhA8;2QLtiK<6kwM)WW~&Of9@i2a{JPX?8@NtC^|! zuhHH51T25Xt#%XSCUTKRry?LYWy~&oy7@g)?mMfehu5d6`EQL)U7x1zp5__UP`i3} z>gvyMu}8gsb#i*ehRONUdd4e5dS_*RG~}NNDxTvF?vHea-20{x(O3;^n7sNAJ0q06 zs1`I@{c0q~h9)MsIaS}Nc1GQVTN>u))149jtn|;Ae^&AHVrL>cX&7nYcbcKR*x8f` zaZ0~bJ=K};NH^tH_jHEiO@TMuJjy+t>f{$*>}+IUM>>-Wzw3*stKXodBb_z=X#iTm z-KRUZ`DYDvKP`rO&y_N`M>?yTwxT%KKGGSV$PEg;2ZyHSH;l#0-=0+YEJdwHM}*~H zq1|(x-1)iAc(nVSxPZrjdJeYD7sx@rKn{e6$vJpDmmn*-ikOC|s`sJ(X}y46W~sr{RgIYj;d+f*o$lUF4>Hsj_vY%$F+rP$~1J z%6_Pn`BG&YOPMc6(vSp08n81lv2t{HY}3e?;24tv7#SN$X=>qx(dpp{m5z;#4sRNn zn)@m$deewrNt1IwgUZp5%7&!7SB!S1KBw1LtsEViyuM{@Me2;vl$xFvv3`HpKNI7l zE7jiE*yQtiI5w=8Csa?B0c32LSB55rM>|7;Kr~RZlh5mxDr?pN<=CdN5fxtFGMZLQ zOl;h^Q5}xyc6<~-xf;z7xC6ALN?oGnq|R22ry=q7rpar&R;(0Pj83nh%GlWSh=23& zzM22NoB#e6LtQmF_gi#4_ipa~{*|JYx?eRqJbC?oc<)7Uc5Uz2G<8(4I%Sre`=$yt z>WMM^Mj@Y4W1*1@8?*Yu!$b4rkt7kJ|ovt~0a}>pIlfJS-p#2%ayF>(V`qk2V)z zm!>pk5z#c9(;|Lz^bX^i-@eJj_#AYSYA~VGus| zA4H<5Yo|q2)kS(B>U$aa@99GS7qUgX_w?q(*lnXLG!ESfyYG28W0@H5trBD^)Bi>7 z2^!L`>W+;)GJ2=5_eY(nH}lWrmnaplf`Q?wH~rt_mxlGAxrri)e16ZrlV4hi#I1vu zhs5~;{`a|r^TiXRFn8l*d=GD9m6%lx{F%rm@tylVWvbfQ_(RQ;@9T-kr^hRiL08kO zU;d9&8ymZ0l#X*-V`J*fH}YPFvE!5T|0=i4uUfusogk5kP=6mzBdaKq+^vD|^CMtt zJ`4WTwa;^N?X|I0X?Tr@{<<(VE>YAE;*ds~D>z544h`r>H)|TlNAS%3G7_~(0FPxb zR4}2@tMmWL!=_@smPmkZ6|J6zbnZsNuExJ5eQ{gn@Z4tRqD{z_Y}rKa_uFdo+Pv=X zU7eBXYpFGwZ2^o3_*MEYC)Jnai9|Y+7IT!18=tG&PJ#T`;>!&nAOoQyo zgzTgkaBA-NKAZ#rMq}f~6{ADr<3RDW`plmA{M%4jyfXhY@ZYs>iuZ@~gZK{(iHS85 z)q#lx+nD|htx{8#a-m=dqZ8zUR=P%ge$$UAQH#>t|6#Sn@Y??^cqZrmJ-}Z3bE9Kq zXuZZ$@R1P)B1UqpzsP_8Fc0sCXk+fXQwyKd|5vOMR1zNFVW#l9y;Rs z#o(}SXPhb+TA#9X&;Qz(UY(qu@5r(Cj}*tm#);KJYz &40Tg@BFui#J*$e#>P+* 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 literal 0 HcmV?d00001