From d05a9e3296f73f2309a835c02eef399cccdd19ec Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Wed, 25 May 2022 21:08:19 +0200 Subject: [PATCH 01/13] .NET 6, Fix Warnings, ExpressionWriter as source generator --- .../Shaolinq.AsyncRewriter.Tool.csproj | 2 +- .../CompilationLookup.cs | 4 +- .../GeneratedAsyncMethodSubstitutor.cs | 2 +- .../{ => Generators}/AsyncSourceGenerator.cs | 3 +- .../MethodInvocationInspector.cs | 6 +- src/Shaolinq.AsyncRewriter/Rewriter.cs | 8 +- .../Shaolinq.AsyncRewriter.target | 12 +-- src/Shaolinq.ExpressionWriter.Tool/Program.cs | 42 +++++++++++ .../Shaolinq.ExpressionWriter.Tool.csproj | 14 ++++ .../ExpressionWriterSourceGenerator.cs | 26 +++++++ src/Shaolinq.ExpressionWriter/Program.cs | 47 ------------ .../Shaolinq.ExpressionWriter.csproj | 11 ++- .../Shaolinq.Postgres.DotConnect.csproj | 38 +++++++--- src/Shaolinq.Postgres.DotConnect/app.config | 73 ++++++++++++++++++- .../packages.config | 11 ++- .../Shaolinq.SqlServer.csproj | 4 + ...iteAutoIncrementPrimaryKeyColumnReducer.cs | 5 +- src/Shaolinq.sln | 18 +++++ .../Computed/ComputedExpressionParser.cs | 9 +-- .../Persistence/Linq/ProjectionBuilder.cs | 2 +- src/Shaolinq/Persistence/Linq/QueryBinder.cs | 6 +- src/Shaolinq/Shaolinq.csproj | 26 +++---- .../AsyncRewriterTests.cs | 4 +- .../LambdaTests.cs | 6 +- .../Shaolinq.AsyncRewriter.Tests.csproj | 4 +- .../Shaolinq.ExpressionWriter.Tests.csproj | 3 +- tests/Shaolinq.Tests/FixedDate.cs | 4 +- tests/Shaolinq.Tests/LinqTests.cs | 2 + tests/Shaolinq.Tests/Shaolinq.Tests.csproj | 3 +- tests/Shaolinq.Tests/TestModel/Person.cs | 2 +- 30 files changed, 269 insertions(+), 128 deletions(-) rename src/Shaolinq.AsyncRewriter/{ => Generators}/AsyncSourceGenerator.cs (88%) create mode 100644 src/Shaolinq.ExpressionWriter.Tool/Program.cs create mode 100644 src/Shaolinq.ExpressionWriter.Tool/Shaolinq.ExpressionWriter.Tool.csproj create mode 100644 src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs delete mode 100644 src/Shaolinq.ExpressionWriter/Program.cs diff --git a/src/Shaolinq.AsyncRewriter.Tool/Shaolinq.AsyncRewriter.Tool.csproj b/src/Shaolinq.AsyncRewriter.Tool/Shaolinq.AsyncRewriter.Tool.csproj index 2bc4df1b..379ac1e6 100644 --- a/src/Shaolinq.AsyncRewriter.Tool/Shaolinq.AsyncRewriter.Tool.csproj +++ b/src/Shaolinq.AsyncRewriter.Tool/Shaolinq.AsyncRewriter.Tool.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 diff --git a/src/Shaolinq.AsyncRewriter/CompilationLookup.cs b/src/Shaolinq.AsyncRewriter/CompilationLookup.cs index 72c02355..3ddaeb73 100644 --- a/src/Shaolinq.AsyncRewriter/CompilationLookup.cs +++ b/src/Shaolinq.AsyncRewriter/CompilationLookup.cs @@ -29,7 +29,7 @@ private bool MethodIsPublicOrAccessibleFromCompilation(IMethodSymbol method) if ((method.DeclaredAccessibility == Accessibility.Internal || method.DeclaredAccessibility == Accessibility.ProtectedOrInternal) - && Equals(method.ContainingAssembly, this.compilation.Assembly)) + && SymbolEqualityComparer.Default.Equals(method.ContainingAssembly, this.compilation.Assembly)) { return true; } @@ -61,7 +61,7 @@ public List GetExtensionMethods(string name, ITypeSymbol type) } } - return retval.OrderBy(c => c.Key.ContainingAssembly.Equals(this.compilation.Assembly) ? 0 : c.Value + 1).Select(c => c.Key).ToList(); + return retval.OrderBy(c => SymbolEqualityComparer.Default.Equals(c.Key.ContainingAssembly,this.compilation.Assembly) ? 0 : c.Value + 1).Select(c => c.Key).ToList(); } private void Visit(Compilation compilationNode) diff --git a/src/Shaolinq.AsyncRewriter/GeneratedAsyncMethodSubstitutor.cs b/src/Shaolinq.AsyncRewriter/GeneratedAsyncMethodSubstitutor.cs index 8959a4fb..a1354e3b 100644 --- a/src/Shaolinq.AsyncRewriter/GeneratedAsyncMethodSubstitutor.cs +++ b/src/Shaolinq.AsyncRewriter/GeneratedAsyncMethodSubstitutor.cs @@ -41,7 +41,7 @@ public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax if (result.Symbol == null) { var newNode = node.WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(node.ArgumentList.Arguments - .Where(c => GetArgumentType(c) != this.cancellationTokenSymbol)))); + .Where(c => !SymbolEqualityComparer.Default.Equals(GetArgumentType(c),this.cancellationTokenSymbol))))); var visited = Visit(node.Expression); diff --git a/src/Shaolinq.AsyncRewriter/AsyncSourceGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs similarity index 88% rename from src/Shaolinq.AsyncRewriter/AsyncSourceGenerator.cs rename to src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs index 09d662bd..d99a0fe9 100644 --- a/src/Shaolinq.AsyncRewriter/AsyncSourceGenerator.cs +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs @@ -1,7 +1,7 @@ using System; using Microsoft.CodeAnalysis; -namespace Shaolinq.AsyncRewriter +namespace Shaolinq.AsyncRewriter.Generators { [Generator] public class AsyncSourceGenerator : ISourceGenerator @@ -22,7 +22,6 @@ public void Execute(GeneratorExecutionContext context) } catch (Exception ex) { - //Console.WriteLine(ex.ToString()); Console.Error.WriteLine(ex.ToString()); throw; } diff --git a/src/Shaolinq.AsyncRewriter/MethodInvocationInspector.cs b/src/Shaolinq.AsyncRewriter/MethodInvocationInspector.cs index e559bb93..a0498ff5 100644 --- a/src/Shaolinq.AsyncRewriter/MethodInvocationInspector.cs +++ b/src/Shaolinq.AsyncRewriter/MethodInvocationInspector.cs @@ -114,7 +114,7 @@ public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax if (result.Symbol == null) { var newNode = node.WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(node.ArgumentList.Arguments - .Where(c => GetArgumentType(c) != this.cancellationTokenSymbol)))); + .Where(c => !SymbolEqualityComparer.Default.Equals(GetArgumentType(c), this.cancellationTokenSymbol))))); var visited = Visit(node.Expression); @@ -270,9 +270,9 @@ public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax } } - if (candidate.ExtensionMethodNormalizingParameters().Any(c => c.Type == this.cancellationTokenSymbol)) + if (candidate.ExtensionMethodNormalizingParameters().Any(c => SymbolEqualityComparer.Default.Equals(c.Type, this.cancellationTokenSymbol))) { - cancellationTokenPos = candidate.ExtensionMethodNormalizingParameters().Count(c => c.Type != this.cancellationTokenSymbol); + cancellationTokenPos = candidate.ExtensionMethodNormalizingParameters().Count(c => !SymbolEqualityComparer.Default.Equals(c.Type, this.cancellationTokenSymbol)); } else { diff --git a/src/Shaolinq.AsyncRewriter/Rewriter.cs b/src/Shaolinq.AsyncRewriter/Rewriter.cs index 4140607a..5fe2d9d9 100644 --- a/src/Shaolinq.AsyncRewriter/Rewriter.cs +++ b/src/Shaolinq.AsyncRewriter/Rewriter.cs @@ -320,11 +320,11 @@ private bool AllMethodsInClassShouldBeAsync(ITypeSymbol type) if (x.Expression.ToString().Equals("false", StringComparison.OrdinalIgnoreCase)) { - return type == initialType; + return SymbolEqualityComparer.Default.Equals(type, initialType); } } - if (attributeSyntax != null && type == initialType) + if (attributeSyntax != null && SymbolEqualityComparer.Default.Equals(type, initialType)) { return true; } @@ -494,7 +494,7 @@ private void ValidateAsyncMethod(MethodDeclarationSyntax methodSyntax, SemanticM { foreach (var result in results) { - if (!result.ReplacementMethodSymbol.Equals(methodSymbol)) + if (!SymbolEqualityComparer.Default.Equals(result.ReplacementMethodSymbol, methodSymbol)) { this.log.LogWarning($"Async method call possible in {result.Position.GetLineSpan()}"); this.log.LogWarning($"Replace {result.MethodInvocationSyntax.NormalizeWhitespace()} with {result.ReplacementExpressionSyntax.NormalizeWhitespace()}"); @@ -689,7 +689,7 @@ private MethodDeclarationSyntax RewriteMethodAsync(MethodDeclarationSyntax metho { var first = attribute.ConstructorArguments.First(); - if (first.Type.Equals(this.methodAttributesSymbol)) + if (SymbolEqualityComparer.Default.Equals(first.Type, this.methodAttributesSymbol)) { var methodAttributes = (MethodAttributes)Enum.ToObject(typeof(MethodAttributes), Convert.ToInt32(first.Value)); diff --git a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target index 54b7369a..e0046e59 100644 --- a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target +++ b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target @@ -1,7 +1,7 @@ - "..\Shaolinq.AsyncRewriter\bin\$(Configuration)\net5.0\Shaolinq.AsyncRewriter.exe" + "..\Shaolinq.AsyncRewriter\bin\$(Configuration)\net6.0\Shaolinq.AsyncRewriter.exe" - - + + --> + \ No newline at end of file diff --git a/src/Shaolinq.ExpressionWriter.Tool/Program.cs b/src/Shaolinq.ExpressionWriter.Tool/Program.cs new file mode 100644 index 00000000..a0849ff1 --- /dev/null +++ b/src/Shaolinq.ExpressionWriter.Tool/Program.cs @@ -0,0 +1,42 @@ +namespace Shaolinq.ExpressionWriter.Tool; + +public class Program +{ + public static void Main(string[] args) + { + string output = null; + string writer = null; + string[] input = null; + + for (var i = 0; i < args.Length; i++) + { + var arg = args[i]; + + if (arg == "-writer") + { + writer = args[++i]; + } + else if (arg == "-output") + { + output = args[++i]; + } + else + { + input = new string[args.Length - i]; + + Array.Copy(args, i, input, 0, args.Length - i); + + break; + } + } + + if (writer == "comparer") + { + ExpressionComparerWriter.Write(input, output); + } + else if (writer == "hasher") + { + ExpressionHasherWriter.Write(input, output); + } + } +} \ No newline at end of file diff --git a/src/Shaolinq.ExpressionWriter.Tool/Shaolinq.ExpressionWriter.Tool.csproj b/src/Shaolinq.ExpressionWriter.Tool/Shaolinq.ExpressionWriter.Tool.csproj new file mode 100644 index 00000000..492e521c --- /dev/null +++ b/src/Shaolinq.ExpressionWriter.Tool/Shaolinq.ExpressionWriter.Tool.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs b/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs new file mode 100644 index 00000000..30618c72 --- /dev/null +++ b/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.CodeAnalysis; + +namespace Shaolinq.ExpressionWriter.Generators +{ + [Generator] + public class ExpressionWriterSourceGenerator : ISourceGenerator + { + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + try + { + + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.ToString()); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Shaolinq.ExpressionWriter/Program.cs b/src/Shaolinq.ExpressionWriter/Program.cs deleted file mode 100644 index 0ac59aaa..00000000 --- a/src/Shaolinq.ExpressionWriter/Program.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - -using System; - -namespace Shaolinq.ExpressionWriter -{ - public class Program - { - public static void Main(string[] args) - { - string output = null; - string writer = null; - string[] input = null; - - for (var i = 0; i < args.Length; i++) - { - var arg = args[i]; - - if (arg == "-writer") - { - writer = args[++i]; - } - else if (arg == "-output") - { - output = args[++i]; - } - else - { - input = new string[args.Length - i]; - - Array.Copy(args, i, input, 0, args.Length - i); - - break; - } - } - - if (writer == "comparer") - { - ExpressionComparerWriter.Write(input, output); - } - else if (writer == "hasher") - { - ExpressionHasherWriter.Write(input, output); - } - } - } -} diff --git a/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj b/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj index 6b818f96..0638c9cc 100644 --- a/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj +++ b/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj @@ -1,15 +1,18 @@ - net461;net5.0 - Exe Shaolinq.ExpressionWriter Shaolinq.ExpressionWriter + netstandard2.0 - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj b/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj index 7e536748..9eeae922 100644 --- a/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj +++ b/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj @@ -10,7 +10,7 @@ Properties Shaolinq.Postgres.DotConnect Shaolinq.Postgres.DotConnect - v4.5.2 + v4.8 512 @@ -100,22 +100,40 @@ false - - ..\packages\dotConnect.Express.for.PostgreSQL.7.10.1061\lib\Devart.Data.dll + + ..\packages\dotConnect.Express.for.PostgreSQL.7.24.2066\lib\Devart.Data.dll - - ..\packages\dotConnect.Express.for.PostgreSQL.7.10.1061\lib\Devart.Data.PostgreSql.dll + + ..\packages\dotConnect.Express.for.PostgreSQL.7.24.2066\lib\Devart.Data.PostgreSql.dll - - ..\packages\Platform.NET.1.2.5\lib\net452\Platform.dll + + + ..\packages\Contrib.Platform.NET.2.0.0\lib\netstandard2.0\Platform.dll - - ..\packages\Platform.Xml.Serialization.1.2.5\lib\net452\Platform.Xml.Serialization.dll + + ..\packages\Contrib.Platform.Xml.Serialization.2.0.0\lib\netstandard2.0\Platform.Xml.Serialization.dll + + + ..\packages\System.Configuration.ConfigurationManager.6.0.0\lib\net461\System.Configuration.ConfigurationManager.dll + 3.5 + + + + + ..\packages\System.Security.AccessControl.6.0.0\lib\net461\System.Security.AccessControl.dll + + + ..\packages\System.Security.Permissions.6.0.0\lib\net461\System.Security.Permissions.dll + + + ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll + + @@ -194,5 +212,5 @@ - + \ No newline at end of file diff --git a/src/Shaolinq.Postgres.DotConnect/app.config b/src/Shaolinq.Postgres.DotConnect/app.config index 677cb24d..4153bcf3 100644 --- a/src/Shaolinq.Postgres.DotConnect/app.config +++ b/src/Shaolinq.Postgres.DotConnect/app.config @@ -4,5 +4,74 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Shaolinq.Postgres.DotConnect/packages.config b/src/Shaolinq.Postgres.DotConnect/packages.config index 859b6eed..47cccc26 100644 --- a/src/Shaolinq.Postgres.DotConnect/packages.config +++ b/src/Shaolinq.Postgres.DotConnect/packages.config @@ -1,6 +1,11 @@  - - - + + + + + + + + \ No newline at end of file diff --git a/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj b/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj index 699298ea..f7f705ea 100644 --- a/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj +++ b/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/src/Shaolinq.Sqlite/SqliteAutoIncrementPrimaryKeyColumnReducer.cs b/src/Shaolinq.Sqlite/SqliteAutoIncrementPrimaryKeyColumnReducer.cs index ff6e375f..f012cd33 100644 --- a/src/Shaolinq.Sqlite/SqliteAutoIncrementPrimaryKeyColumnReducer.cs +++ b/src/Shaolinq.Sqlite/SqliteAutoIncrementPrimaryKeyColumnReducer.cs @@ -106,9 +106,8 @@ protected override Expression VisitColumnDefinition(SqlColumnDefinitionExpressio if (autoIncrement) { - newConstraints = newConstraints - .Where(c => !c.NotNull) - .Prepend(new SqlConstraintExpression(ConstraintType.PrimaryKey)); + EnumerableUtils.Prepend(newConstraints = newConstraints + .Where(c => !c.NotNull), new SqlConstraintExpression(ConstraintType.PrimaryKey)); } if (ReferenceEquals(newConstraints, columnDefinitionExpression.ConstraintExpressions)) diff --git a/src/Shaolinq.sln b/src/Shaolinq.sln index 11e2ad4c..92fe8412 100644 --- a/src/Shaolinq.sln +++ b/src/Shaolinq.sln @@ -48,6 +48,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.ExpressionWriter.T EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.AsyncRewriter.Tool", "Shaolinq.AsyncRewriter.Tool\Shaolinq.AsyncRewriter.Tool.csproj", "{F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AsyncRewriter", "AsyncRewriter", "{BB073B54-12FA-498C-A94A-9D154F4D00EE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExpressionWriter", "ExpressionWriter", "{C91EDDBA-2D1C-478A-84C8-88A7523B88B8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.ExpressionWriter.Tool", "Shaolinq.ExpressionWriter.Tool\Shaolinq.ExpressionWriter.Tool.csproj", "{3725382B-D77B-431F-B51B-7FDFB9687F4B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -106,6 +112,10 @@ Global {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41}.Debug|Any CPU.Build.0 = Debug|Any CPU {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41}.Release|Any CPU.ActiveCfg = Release|Any CPU {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41}.Release|Any CPU.Build.0 = Release|Any CPU + {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -113,4 +123,12 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6F0187C2-422B-42D1-A61E-1A265A4DE8CE} EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} + {1F63CC9A-3D25-44A1-919C-9731F8ED11DC} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} + {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} + {BC3ECC35-58F4-45ED-A801-95F2D5C4CDFD} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} + {DA01B743-A340-4B07-9B6A-EE37947BD2CE} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} + {3725382B-D77B-431F-B51B-7FDFB9687F4B} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} + EndGlobalSection EndGlobal diff --git a/src/Shaolinq/Persistence/Computed/ComputedExpressionParser.cs b/src/Shaolinq/Persistence/Computed/ComputedExpressionParser.cs index 9b915410..3306cd9b 100644 --- a/src/Shaolinq/Persistence/Computed/ComputedExpressionParser.cs +++ b/src/Shaolinq/Persistence/Computed/ComputedExpressionParser.cs @@ -482,14 +482,7 @@ private bool DoesNamespaceResolve(string fullNamespace) this.namespaces = new HashSet(); this.referencedTypesByName.Select(c => c.Value.Namespace).ForEach(c => this.namespaces.Add(c)); - try - { - AppDomain.CurrentDomain.GetAssemblies().SelectMany(c => c.DefinedTypes).ForEach(c => this.namespaces.Add(c.Namespace)); - } - catch (Exception e) - { - throw; - } + AppDomain.CurrentDomain.GetAssemblies().SelectMany(c => c.DefinedTypes).ForEach(c => this.namespaces.Add(c.Namespace)); } return this.namespaces.Contains(fullNamespace); diff --git a/src/Shaolinq/Persistence/Linq/ProjectionBuilder.cs b/src/Shaolinq/Persistence/Linq/ProjectionBuilder.cs index 41928653..c1cce334 100644 --- a/src/Shaolinq/Persistence/Linq/ProjectionBuilder.cs +++ b/src/Shaolinq/Persistence/Linq/ProjectionBuilder.cs @@ -312,7 +312,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp var arguments = (IEnumerable)VisitExpressionList(methodCallExpression.Arguments.Skip(1).ToArray()); this.atRootLevel = savedAtRootLevel; - retval = Expression.Call(instance, methodCallExpression.Method, arguments.Prepend(firstArg)); + retval = Expression.Call(instance, methodCallExpression.Method, EnumerableUtils.Prepend(arguments, firstArg)); } else { diff --git a/src/Shaolinq/Persistence/Linq/QueryBinder.cs b/src/Shaolinq/Persistence/Linq/QueryBinder.cs index d958fdfb..73828083 100644 --- a/src/Shaolinq/Persistence/Linq/QueryBinder.cs +++ b/src/Shaolinq/Persistence/Linq/QueryBinder.cs @@ -1093,11 +1093,11 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp case "AddHours": return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddTimeSpan, Visit(methodCallExpression.Object), new SqlFunctionCallExpression(typeof(TimeSpan), SqlFunction.TimeSpanFromHours, VisitExpressionList(methodCallExpression.Arguments))); case "AddDays": - return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddDays, VisitExpressionList(methodCallExpression.Arguments).Prepend(Visit(methodCallExpression.Object))); + return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddDays, EnumerableUtils.Prepend(VisitExpressionList(methodCallExpression.Arguments), Visit(methodCallExpression.Object))); case "AddMonths": - return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddMonths, VisitExpressionList(methodCallExpression.Arguments).Prepend(Visit(methodCallExpression.Object))); + return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddMonths, EnumerableUtils.Prepend(methodCallExpression.Arguments, Visit(methodCallExpression.Object))); case "AddYears": - return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddYears, VisitExpressionList(methodCallExpression.Arguments).Prepend(Visit(methodCallExpression.Object))); + return new SqlFunctionCallExpression(typeof(DateTime), SqlFunction.DateTimeAddYears, EnumerableUtils.Prepend(methodCallExpression.Arguments, Visit(methodCallExpression.Object))); } } diff --git a/src/Shaolinq/Shaolinq.csproj b/src/Shaolinq/Shaolinq.csproj index d7fd3d30..8fa52b9f 100644 --- a/src/Shaolinq/Shaolinq.csproj +++ b/src/Shaolinq/Shaolinq.csproj @@ -23,26 +23,24 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - "..\Shaolinq.ExpressionWriter\bin\$(Configuration)\net5.0\Shaolinq.ExpressionWriter.exe" - - - - - - - - - + + + - + + + + + + + diff --git a/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs b/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs index 12463fe5..c1ac53e7 100644 --- a/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs +++ b/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs @@ -48,7 +48,7 @@ private static TestCaseData GetTestCaseData(string name, params string[] inputFi public void TestRewrite(params string[] inputFiles) { var rewriter = new Rewriter(); - var root = Path.Combine(Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath), "RewriteTests"); + var root = Path.Combine(Path.GetDirectoryName(new Uri(GetType().Assembly.Location).LocalPath), "RewriteTests"); var result = rewriter.RewriteAndMerge(inputFiles.Select(c => Path.Combine(root, c)).ToArray()); @@ -61,7 +61,7 @@ public void TestRewrite(params string[] inputFiles) public void TestRewriteCompile(params string[] inputFiles) { var rewriter = new Rewriter(); - var root = Path.Combine(Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath), "RewriteTests"); + var root = Path.Combine(Path.GetDirectoryName(new Uri(GetType().Assembly.Location).LocalPath), "RewriteTests"); var files = new List(inputFiles) {"RewriteAsyncAttribute.cs"}; var references = new MetadataReference[] { diff --git a/tests/Shaolinq.AsyncRewriter.Tests/LambdaTests.cs b/tests/Shaolinq.AsyncRewriter.Tests/LambdaTests.cs index 73409849..fb5e6808 100644 --- a/tests/Shaolinq.AsyncRewriter.Tests/LambdaTests.cs +++ b/tests/Shaolinq.AsyncRewriter.Tests/LambdaTests.cs @@ -18,7 +18,7 @@ public static void Foo() public static Task FooAsync() { - return default(Task); + return default; } public static void Act(Action action) @@ -27,7 +27,7 @@ public static void Act(Action action) public static Task ActAsync(Action action) { - return default(Task); + return default; } [RewriteAsync] @@ -40,7 +40,7 @@ public void Act1() public void Test() { var rewriter = new Rewriter(); - var root = Path.GetDirectoryName(new Uri(GetType().Assembly.CodeBase).LocalPath); + var root = Path.GetDirectoryName(new Uri(GetType().Assembly.Location).LocalPath); var paths = new List { "LambdaTests.cs" }; var result = rewriter.RewriteAndMerge(paths.Select(c => Path.Combine(root, c)).ToArray()); diff --git a/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj b/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj index 2f7e5624..b03efb56 100644 --- a/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj +++ b/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj @@ -1,7 +1,7 @@  - net461;net5.0 + net6.0 false @@ -10,7 +10,7 @@ - + diff --git a/tests/Shaolinq.ExpressionWriter.Tests/Shaolinq.ExpressionWriter.Tests.csproj b/tests/Shaolinq.ExpressionWriter.Tests/Shaolinq.ExpressionWriter.Tests.csproj index 82225cd7..e433faa9 100644 --- a/tests/Shaolinq.ExpressionWriter.Tests/Shaolinq.ExpressionWriter.Tests.csproj +++ b/tests/Shaolinq.ExpressionWriter.Tests/Shaolinq.ExpressionWriter.Tests.csproj @@ -1,8 +1,7 @@  - net461;net5.0 - + net6.0 false diff --git a/tests/Shaolinq.Tests/FixedDate.cs b/tests/Shaolinq.Tests/FixedDate.cs index af20fa0b..393f74c5 100644 --- a/tests/Shaolinq.Tests/FixedDate.cs +++ b/tests/Shaolinq.Tests/FixedDate.cs @@ -76,12 +76,12 @@ public static implicit operator FixedDate(DateTime value) public static implicit operator FixedDate?(DateTime value) { - return value == null ? null : (FixedDate?)new FixedDate(value); + return new FixedDate(value); } public static implicit operator FixedDate? (DateTime? value) { - return value == null ? null : (FixedDate?)new FixedDate(value.Value); + return value == null ? null : new FixedDate(value.Value); } } diff --git a/tests/Shaolinq.Tests/LinqTests.cs b/tests/Shaolinq.Tests/LinqTests.cs index c071578e..d30d6357 100644 --- a/tests/Shaolinq.Tests/LinqTests.cs +++ b/tests/Shaolinq.Tests/LinqTests.cs @@ -3547,7 +3547,9 @@ public void Test_Rollback_DataAccessScope_Inside_TransactionScope() { using (var dataAccessScope = DataAccessScope.CreateReadCommitted()) { +#pragma warning disable CS8073 this.model.Students.SingleOrDefault(c => c.Id == null); +#pragma warning restore CS8073 } } } diff --git a/tests/Shaolinq.Tests/Shaolinq.Tests.csproj b/tests/Shaolinq.Tests/Shaolinq.Tests.csproj index 88d0e7c9..3776f2f4 100644 --- a/tests/Shaolinq.Tests/Shaolinq.Tests.csproj +++ b/tests/Shaolinq.Tests/Shaolinq.Tests.csproj @@ -1,8 +1,7 @@  - net461;net5.0 - + net6.0 false diff --git a/tests/Shaolinq.Tests/TestModel/Person.cs b/tests/Shaolinq.Tests/TestModel/Person.cs index 49c82117..2b618abb 100644 --- a/tests/Shaolinq.Tests/TestModel/Person.cs +++ b/tests/Shaolinq.Tests/TestModel/Person.cs @@ -13,7 +13,7 @@ public abstract class Person [DefaultValue(Value = "Anonymous")] public abstract string Firstname { get; set; } - [Index(LowercaseIndex = true), PersistedMember, SizeConstraint(MaximumLength = 64)] + [Index(Lowercase = true), PersistedMember, SizeConstraint(MaximumLength = 64)] public abstract string Email { get; set; } [PersistedMember] From 8949ae244b7de43a2f69d666ae8c4f5bfa5eba63 Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Sun, 19 Jun 2022 23:15:32 +0200 Subject: [PATCH 02/13] AsyncRewriter: add nuget config to proj file --- .../Shaolinq.AsyncRewriter.csproj | 12 +++++++++++- src/Shaolinq.AsyncRewriter/TypeSymbolExtensions.cs | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj index f93fa4c1..1616e14e 100644 --- a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj +++ b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj @@ -1,14 +1,24 @@  - netstandard2.0 + netstandard2.0 Shaolinq.AsyncRewriter Shaolinq.AsyncRewriter + false + Shaolinq.AsyncRewriter + Shaolinq AsyncRewriter + + Stop copying and pasting code in order to support Async/Await! Shaolinq.AsyncRewriter generates async methods from your sync methods using Roslyn. + AsyncRewriter is used extensively by the Shaolinq ORM/LINQ project. + + shaolinq async rewriter asyncrewriter await codegen roslyn + + diff --git a/src/Shaolinq.AsyncRewriter/TypeSymbolExtensions.cs b/src/Shaolinq.AsyncRewriter/TypeSymbolExtensions.cs index ed5d1f32..ffc505c0 100644 --- a/src/Shaolinq.AsyncRewriter/TypeSymbolExtensions.cs +++ b/src/Shaolinq.AsyncRewriter/TypeSymbolExtensions.cs @@ -37,7 +37,7 @@ public int GetHashCode(ITypeSymbol obj) internal static bool EqualsToIgnoreGenericParameters(this ITypeSymbol self, ITypeSymbol other) { - if (self == other) + if (SymbolEqualityComparer.Default.Equals(self, other)) { return true; } @@ -88,7 +88,7 @@ internal static bool EqualsToIgnoreGenericParameters(this ITypeSymbol self, ITyp public static int? IsAssignableFrom(this ITypeSymbol self, ITypeSymbol other, int? depth) { - if (self == other) + if (SymbolEqualityComparer.Default.Equals(self, other)) { return depth; } From 147039d9a0f4bebb310fb7ffe5643fbcf32aefdb Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Mon, 20 Jun 2022 11:17:50 +0200 Subject: [PATCH 03/13] Update .gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5c520fd3..168d8f85 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,7 @@ $RECYCLE.BIN/ lib/Packages/ src/packages/ /src/.vs/Shaolinq/v15/sqlite3/storage.ide + +# Rider IDE + +.idea \ No newline at end of file From e65c44b185b82200cae4abcc60b7810fe0a6c96b Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Mon, 20 Jun 2022 19:41:39 +0200 Subject: [PATCH 04/13] Add sandbox and another generator --- .../AsyncRewriteAttributeClassGenerator.cs | 66 +++++++++++++++++++ ...nq.AsyncRewriter.AttributeGenerator.csproj | 12 ++++ .../AsyncRewriteAttributeClassGenerator.cs | 65 ++++++++++++++++++ .../Generators/AsyncSourceGenerator.cs | 10 +-- .../Shaolinq.AsyncRewriter.csproj | 5 +- src/Shaolinq.sln | 44 ++++++++----- .../Shaolinq.AsyncRewriter.Sandbox/Class1.cs | 48 ++++++++++++++ .../Shaolinq.AsyncRewriter.Sandbox.csproj | 13 ++++ 8 files changed, 243 insertions(+), 20 deletions(-) create mode 100644 src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs create mode 100644 src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj create mode 100644 src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs create mode 100644 tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs create mode 100644 tests/Shaolinq.AsyncRewriter.Sandbox/Shaolinq.AsyncRewriter.Sandbox.csproj diff --git a/src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs b/src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs new file mode 100644 index 00000000..62f65a0e --- /dev/null +++ b/src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs @@ -0,0 +1,66 @@ +using System.Diagnostics; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using System; + +namespace Shaolinq.AsyncRewriter.AttributeGenerator +{ + [Generator] + public class AsyncRewriteAttributeClassGenerator : ISourceGenerator + { + private const string AttributeClassName = "RewriteAsyncAttribute"; + + public static SourceText SourceText(string attributeNamespace, string app) => Microsoft.CodeAnalysis.Text.SourceText.From($@" +// Generated +using System; +using System.Reflection; + +namespace {attributeNamespace} +{{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] + public class RewriteAsyncAttribute{app} : Attribute + {{ + public RewriteAsyncAttribute{app}() + : this(default(MethodAttributes)) + {{ + }} + + public RewriteAsyncAttribute{app}(MethodAttributes methodAttributes) + {{ + this.MethodAttributes = methodAttributes; + }} + + public bool ContinueOnCapturedContext {{ get; set; }} + public bool ApplyToDescendents {{ get; set; }} + public MethodAttributes MethodAttributes {{ get; set; }} + }} +}} +// End +", Encoding.UTF8); + + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + if (!Debugger.IsAttached) + { + //Debugger.Launch(); + } + try + { + context.AddSource(AttributeClassName, SourceText(context.Compilation.AssemblyName.ToString(), "")); + context.AddSource("Another", SourceText(context.Compilation.AssemblyName.ToString(), "Two")); + context.AddSource("Three", SourceText(context.Compilation.AssemblyName.ToString(), "Three")); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.ToString()); + throw; + } + + } + } +} diff --git a/src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj b/src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj new file mode 100644 index 00000000..f231b0ad --- /dev/null +++ b/src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs new file mode 100644 index 00000000..9623f140 --- /dev/null +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs @@ -0,0 +1,65 @@ +using System.Diagnostics; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using System; + +namespace Shaolinq.AsyncRewriter.Generators +{ + //[Generator] + public class AsyncRewriteAttributeClassGenerator //: ISourceGenerator + { + public const string AttributeClassName = "RewriteAsyncAttribute"; + + public static SourceText SourceText(string attributeNamespace) => Microsoft.CodeAnalysis.Text.SourceText.From($@" +// Generated +using System; +using System.Reflection; + +namespace {attributeNamespace} +{{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] + internal class RewriteAsyncAttribute : Attribute + {{ + public RewriteAsyncAttribute() + : this(default(MethodAttributes)) + {{ + }} + + public RewriteAsyncAttribute(MethodAttributes methodAttributes) + {{ + this.MethodAttributes = methodAttributes; + }} + + public bool ContinueOnCapturedContext {{ get; set; }} + public bool ApplyToDescendents {{ get; set; }} + public MethodAttributes MethodAttributes {{ get; set; }} + }} +}} +// End +", Encoding.UTF8); + + public void Initialize(GeneratorInitializationContext context) + { + // context.RegisterForPostInitialization(ctx => ctx.AddSource("Attributes", StringConstants.Attributes)); + } + + public void Execute(GeneratorExecutionContext context) + { + if (!Debugger.IsAttached) + { + //Debugger.Launch(); + } + try + { + context.AddSource(AttributeClassName, SourceText(context.Compilation.AssemblyName.ToString())); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.ToString()); + throw; + } + + } + } +} \ No newline at end of file diff --git a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs index d99a0fe9..d7348fff 100644 --- a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using Microsoft.CodeAnalysis; namespace Shaolinq.AsyncRewriter.Generators @@ -13,13 +14,14 @@ public void Initialize(GeneratorInitializationContext context) public void Execute(GeneratorExecutionContext context) { var r = new Rewriter(); - try { - var syntaxTree = r.RewriteAndMerge(context.Compilation.SyntaxTrees, context.Compilation.References); + context.AddSource(AsyncRewriteAttributeClassGenerator.AttributeClassName, AsyncRewriteAttributeClassGenerator.SourceText(context.Compilation.AssemblyName.ToString())); - context.AddSource("GeneratedAsync", syntaxTree.ToString()); - } + var syntaxTree = r.RewriteAndMerge(context.Compilation.SyntaxTrees, context.Compilation.References); + + context.AddSource("GeneratedAsync", syntaxTree.ToString()); + } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); diff --git a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj index 1616e14e..e01814a7 100644 --- a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj +++ b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj @@ -2,6 +2,7 @@ netstandard2.0 + 3.0.15-anton Shaolinq.AsyncRewriter Shaolinq.AsyncRewriter false @@ -12,10 +13,12 @@ AsyncRewriter is used extensively by the Shaolinq ORM/LINQ project. shaolinq async rewriter asyncrewriter await codegen roslyn + latestmajor + false - + diff --git a/src/Shaolinq.sln b/src/Shaolinq.sln index 92fe8412..5722aa0f 100644 --- a/src/Shaolinq.sln +++ b/src/Shaolinq.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30907.101 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32414.318 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq", "Shaolinq\Shaolinq.csproj", "{0C8321D6-4DF6-4B90-AF5A-92537D4A7E54}" ProjectSection(ProjectDependencies) = postProject @@ -9,19 +9,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq", "Shaolinq\Shaoli {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.Tests", "..\tests\Shaolinq.Tests\Shaolinq.Tests.csproj", "{F5BEB79B-3BCA-46AE-A08E-1B86CDD03616}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.Tests", "..\tests\Shaolinq.Tests\Shaolinq.Tests.csproj", "{F5BEB79B-3BCA-46AE-A08E-1B86CDD03616}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.MySql", "Shaolinq.MySql\Shaolinq.MySql.csproj", "{3020F62F-0078-4202-86EB-DD013294D1F2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.MySql", "Shaolinq.MySql\Shaolinq.MySql.csproj", "{3020F62F-0078-4202-86EB-DD013294D1F2}" ProjectSection(ProjectDependencies) = postProject {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.Postgres", "Shaolinq.Postgres\Shaolinq.Postgres.csproj", "{E79DCCED-1693-4E38-98AC-B988D7429615}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.Postgres", "Shaolinq.Postgres\Shaolinq.Postgres.csproj", "{E79DCCED-1693-4E38-98AC-B988D7429615}" ProjectSection(ProjectDependencies) = postProject {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.Sqlite", "Shaolinq.Sqlite\Shaolinq.Sqlite.csproj", "{5FD0C2B3-F601-452A-8C72-D5962B6A089A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.Sqlite", "Shaolinq.Sqlite\Shaolinq.Sqlite.csproj", "{5FD0C2B3-F601-452A-8C72-D5962B6A089A}" ProjectSection(ProjectDependencies) = postProject {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} EndProjectSection @@ -31,12 +31,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.Postgres.DotConnec {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.SqlServer", "Shaolinq.SqlServer\Shaolinq.SqlServer.csproj", "{1074BF68-A350-48A8-9769-43AD73537879}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.SqlServer", "Shaolinq.SqlServer\Shaolinq.SqlServer.csproj", "{1074BF68-A350-48A8-9769-43AD73537879}" ProjectSection(ProjectDependencies) = postProject {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.Tests.OtherDataAccessObjects", "..\tests\Shaolinq.Tests.OtherDataAccessObjects\Shaolinq.Tests.OtherDataAccessObjects.csproj", "{737A2E9A-A1B9-4BC8-94BD-5327134142CB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.Tests.OtherDataAccessObjects", "..\tests\Shaolinq.Tests.OtherDataAccessObjects\Shaolinq.Tests.OtherDataAccessObjects.csproj", "{737A2E9A-A1B9-4BC8-94BD-5327134142CB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.ExpressionWriter", "Shaolinq.ExpressionWriter\Shaolinq.ExpressionWriter.csproj", "{BC3ECC35-58F4-45ED-A801-95F2D5C4CDFD}" EndProject @@ -46,13 +46,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.AsyncRewriter.Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.ExpressionWriter.Tests", "..\tests\Shaolinq.ExpressionWriter.Tests\Shaolinq.ExpressionWriter.Tests.csproj", "{DA01B743-A340-4B07-9B6A-EE37947BD2CE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.AsyncRewriter.Tool", "Shaolinq.AsyncRewriter.Tool\Shaolinq.AsyncRewriter.Tool.csproj", "{F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.AsyncRewriter.Tool", "Shaolinq.AsyncRewriter.Tool\Shaolinq.AsyncRewriter.Tool.csproj", "{F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AsyncRewriter", "AsyncRewriter", "{BB073B54-12FA-498C-A94A-9D154F4D00EE}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ExpressionWriter", "ExpressionWriter", "{C91EDDBA-2D1C-478A-84C8-88A7523B88B8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.ExpressionWriter.Tool", "Shaolinq.ExpressionWriter.Tool\Shaolinq.ExpressionWriter.Tool.csproj", "{3725382B-D77B-431F-B51B-7FDFB9687F4B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.ExpressionWriter.Tool", "Shaolinq.ExpressionWriter.Tool\Shaolinq.ExpressionWriter.Tool.csproj", "{3725382B-D77B-431F-B51B-7FDFB9687F4B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.AsyncRewriter.Sandbox", "..\tests\Shaolinq.AsyncRewriter.Sandbox\Shaolinq.AsyncRewriter.Sandbox.csproj", "{3F73A8AD-6F5A-4218-8BC9-CCB241137747}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.AsyncRewriter.AttributeGenerator", "Shaolinq.AsyncRewriter.AttributeGenerator\Shaolinq.AsyncRewriter.AttributeGenerator.csproj", "{46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -116,19 +120,29 @@ Global {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {3725382B-D77B-431F-B51B-7FDFB9687F4B}.Release|Any CPU.Build.0 = Release|Any CPU + {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Release|Any CPU.Build.0 = Release|Any CPU + {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6F0187C2-422B-42D1-A61E-1A265A4DE8CE} - EndGlobalSection GlobalSection(NestedProjects) = preSolution + {BC3ECC35-58F4-45ED-A801-95F2D5C4CDFD} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} {318F3A69-3F34-4CE4-8ED5-22EFE2F6C302} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} {1F63CC9A-3D25-44A1-919C-9731F8ED11DC} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} - {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} - {BC3ECC35-58F4-45ED-A801-95F2D5C4CDFD} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} {DA01B743-A340-4B07-9B6A-EE37947BD2CE} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} + {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} {3725382B-D77B-431F-B51B-7FDFB9687F4B} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} + {3F73A8AD-6F5A-4218-8BC9-CCB241137747} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} + {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6F0187C2-422B-42D1-A61E-1A265A4DE8CE} EndGlobalSection EndGlobal diff --git a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs new file mode 100644 index 00000000..35e47412 --- /dev/null +++ b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs @@ -0,0 +1,48 @@ + +namespace Shaolinq.AsyncRewriter.Sandbox +{ + public partial class Class1 + { + [RewriteAsync] + //[Shaolinq.AsyncRewriter.RewriteAsyncNext] + public void Method() => Console.WriteLine("hello"); + + public int Value { get; set; } + } + + public class Class2 + { + public async Task Method() + { + var xx = new Class1(); + //await xx.MethodAsync(); + } + } +} + + + +//namespace Shaolinq.AsyncRewriter.Sandbox +//{ + +// using System; +// using System.Reflection; + +// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] +// internal class RewriteAsyncAttribute : Attribute +// { +// public RewriteAsyncAttribute() +// : this(default(MethodAttributes)) +// { +// } + +// public RewriteAsyncAttribute(MethodAttributes methodAttributes) +// { +// this.MethodAttributes = methodAttributes; +// } + +// public bool ContinueOnCapturedContext { get; set; } +// public bool ApplyToDescendents { get; set; } +// public MethodAttributes MethodAttributes { get; set; } +// } +//} \ No newline at end of file diff --git a/tests/Shaolinq.AsyncRewriter.Sandbox/Shaolinq.AsyncRewriter.Sandbox.csproj b/tests/Shaolinq.AsyncRewriter.Sandbox/Shaolinq.AsyncRewriter.Sandbox.csproj new file mode 100644 index 00000000..461a8efc --- /dev/null +++ b/tests/Shaolinq.AsyncRewriter.Sandbox/Shaolinq.AsyncRewriter.Sandbox.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + From 6cf27bf60b502812bef437299ee6395578644166 Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Mon, 20 Jun 2022 19:53:27 +0200 Subject: [PATCH 05/13] Remove RewriteAsyncAttribute from source control --- src/Shaolinq.MySql/GeneratedAsync.cs | 161 ------------ src/Shaolinq.MySql/RewriteAsyncAttribute.cs | 21 -- src/Shaolinq.MySql/Shaolinq.MySql.csproj | 4 +- src/Shaolinq.Postgres/GeneratedAsync.cs | 149 ----------- .../RewriteAsyncAttribute.cs | 20 -- .../Shaolinq.Postgres.csproj | 4 +- src/Shaolinq.SqlServer/GeneratedAsync.cs | 97 ------- .../RewriteAsyncAttribute.cs | 21 -- .../Shaolinq.SqlServer.csproj | 4 +- src/Shaolinq.Sqlite/GeneratedAsync.cs | 238 ------------------ src/Shaolinq.Sqlite/RewriteAsyncAttribute.cs | 21 -- src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj | 4 +- .../Persistence/RewriteAsyncAttribute.cs | 21 -- .../Shaolinq.AsyncRewriter.Sandbox/Class1.cs | 3 +- 14 files changed, 13 insertions(+), 755 deletions(-) delete mode 100644 src/Shaolinq.MySql/GeneratedAsync.cs delete mode 100644 src/Shaolinq.MySql/RewriteAsyncAttribute.cs delete mode 100644 src/Shaolinq.Postgres/GeneratedAsync.cs delete mode 100644 src/Shaolinq.Postgres/RewriteAsyncAttribute.cs delete mode 100644 src/Shaolinq.SqlServer/GeneratedAsync.cs delete mode 100644 src/Shaolinq.SqlServer/RewriteAsyncAttribute.cs delete mode 100644 src/Shaolinq.Sqlite/GeneratedAsync.cs delete mode 100644 src/Shaolinq.Sqlite/RewriteAsyncAttribute.cs delete mode 100644 src/Shaolinq/Persistence/RewriteAsyncAttribute.cs diff --git a/src/Shaolinq.MySql/GeneratedAsync.cs b/src/Shaolinq.MySql/GeneratedAsync.cs deleted file mode 100644 index 33230ef4..00000000 --- a/src/Shaolinq.MySql/GeneratedAsync.cs +++ /dev/null @@ -1,161 +0,0 @@ -namespace Shaolinq.MySql -{ -#pragma warning disable - using System; - using System.Data; - using System.Threading; - using System.Data.Common; - using System.Threading.Tasks; - using System.Text.RegularExpressions; - using Shaolinq; - using Shaolinq.MySql; - using Shaolinq.Persistence; - using global::MySql.Data.MySqlClient; - - public partial class MySqlSqlDatabaseContext - { - public override Task OpenConnectionAsync() - { - return this.OpenConnectionAsync(CancellationToken.None); - } - - public override async Task OpenConnectionAsync(CancellationToken cancellationToken) - { - var retval = (await base.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)); - using (var command = retval.CreateCommand()) - { - var prefix = this.SqlDialect.GetSyntaxSymbolString(SqlSyntaxSymbol.ParameterPrefix); - var parameter = command.CreateParameter(); - parameter.DbType = DbType.String; - parameter.ParameterName = $"{prefix}param"; - parameter.Value = this.SqlMode ?? "STRICT_ALL_TABLES"; - command.CommandText = $"SET SESSION sql_mode = {prefix}param;"; - command.Parameters.Add(parameter); - await command.ExecuteNonQueryExAsync(this.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - return retval; - } - } -} - -namespace Shaolinq.MySql -{ -#pragma warning disable - using System; - // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - using System.Data; - using System.Threading; - using System.Threading.Tasks; - using System.Linq.Expressions; - using Shaolinq; - using Shaolinq.MySql; - using Shaolinq.Persistence; - - public partial class MySqlSqlTransactionalCommandsContext - { - public override Task CommitAsync() - { - return this.CommitAsync(CancellationToken.None); - } - - public override async Task CommitAsync(CancellationToken cancellationToken) - { - var queue = (IExpressionQueue)this.TransactionContext?.GetAttribute(MySqlSqlDatabaseContext.CommitCleanupQueueKey); - if (queue != null) - { - Expression current; - while ((current = queue.Dequeue()) != null) - { - var formatter = this.SqlDatabaseContext.SqlQueryFormatterManager.CreateQueryFormatter(); - using (var command = (await this.TransactionContext.GetSqlTransactionalCommandsContextAsync(cancellationToken).ConfigureAwait(false)).CreateCommand()) - { - var formatResult = formatter.Format(current); - command.CommandText = formatResult.CommandText; - FillParameters(command, formatResult); - await command.ExecuteNonQueryExAsync(this.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - } - } - - await base.CommitAsync(cancellationToken).ConfigureAwait(false); - } - } -} - -namespace Shaolinq.MySql -{ -#pragma warning disable - using System; - using System.Threading; - using System.Threading.Tasks; - using System.Linq.Expressions; - using Shaolinq; - using Shaolinq.MySql; - using Shaolinq.Persistence; - - public partial class MySqlSqlDatabaseSchemaManager - { - protected override Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options) - { - return this.CreateDatabaseOnlyAsync(dataDefinitionExpressions, options, CancellationToken.None); - } - - protected override async Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options, CancellationToken cancellationToken) - { - var retval = false; - var factory = this.SqlDatabaseContext.CreateDbProviderFactory(); - var overwrite = options == DatabaseCreationOptions.DeleteExistingDatabase; - using (var dbConnection = factory.CreateConnection()) - { - dbConnection.ConnectionString = this.SqlDatabaseContext.ServerConnectionString; - await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false); - using (var command = dbConnection.CreateCommand()) - { - if (overwrite) - { - var drop = false; - command.CommandText = String.Format("SHOW DATABASES;", this.SqlDatabaseContext.DatabaseName); - using (var reader = (await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false))) - { - while ((await reader.ReadAsync(cancellationToken).ConfigureAwait(false))) - { - var s = reader.GetString(0); - if (s.Equals(this.SqlDatabaseContext.DatabaseName) || s.Equals(this.SqlDatabaseContext.DatabaseName.ToLower())) - { - drop = true; - break; - } - } - } - - if (drop) - { - command.CommandText = $"DROP DATABASE {this.SqlDatabaseContext.DatabaseName}"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - command.CommandText = $"CREATE DATABASE {this.SqlDatabaseContext.DatabaseName}\nDEFAULT CHARACTER SET = utf8\nDEFAULT COLLATE = utf8_general_ci;"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - retval = true; - } - else - { - try - { - command.CommandText = $"CREATE DATABASE {this.SqlDatabaseContext.DatabaseName}\nDEFAULT CHARACTER SET = utf8\nDEFAULT COLLATE = utf8_general_ci;"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - retval = true; - } - catch - { - retval = false; - } - } - } - } - - return retval; - } - } -} \ No newline at end of file diff --git a/src/Shaolinq.MySql/RewriteAsyncAttribute.cs b/src/Shaolinq.MySql/RewriteAsyncAttribute.cs deleted file mode 100644 index 6d919078..00000000 --- a/src/Shaolinq.MySql/RewriteAsyncAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - -using System; -using System.Reflection; - -namespace Shaolinq.MySql -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] - internal class RewriteAsyncAttribute - : Attribute - { - public bool ContinueOnCapturedContext { get; } - public MethodAttributes MethodAttributes { get; } - - public RewriteAsyncAttribute(MethodAttributes methodAttributes = default(MethodAttributes), bool continueOnCapturedContext = false) - { - this.MethodAttributes = methodAttributes; - this.ContinueOnCapturedContext = continueOnCapturedContext; - } - } -} diff --git a/src/Shaolinq.MySql/Shaolinq.MySql.csproj b/src/Shaolinq.MySql/Shaolinq.MySql.csproj index 0f659eab..885da343 100644 --- a/src/Shaolinq.MySql/Shaolinq.MySql.csproj +++ b/src/Shaolinq.MySql/Shaolinq.MySql.csproj @@ -13,5 +13,7 @@ - + + + diff --git a/src/Shaolinq.Postgres/GeneratedAsync.cs b/src/Shaolinq.Postgres/GeneratedAsync.cs deleted file mode 100644 index a0e41188..00000000 --- a/src/Shaolinq.Postgres/GeneratedAsync.cs +++ /dev/null @@ -1,149 +0,0 @@ -namespace Shaolinq.Postgres -{ -#pragma warning disable - using System; - // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - using System.Data; - using System.Threading; - using System.Threading.Tasks; - using System.Linq.Expressions; - using Shaolinq; - using Shaolinq.Postgres; - using Shaolinq.Persistence; - using Shaolinq.Persistence.Linq; - - public partial class PostgresSqlDatabaseSchemaManager - { - protected override Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options) - { - return this.CreateDatabaseOnlyAsync(dataDefinitionExpressions, options, CancellationToken.None); - } - - protected override async Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options, CancellationToken cancellationToken) - { - var retval = false; - var factory = this.SqlDatabaseContext.CreateDbProviderFactory(); - var databaseName = this.SqlDatabaseContext.DatabaseName; - var overwrite = options == DatabaseCreationOptions.DeleteExistingDatabase; - this.SqlDatabaseContext.DropAllConnections(); - using (var dbConnection = factory.CreateConnection()) - { - dbConnection.ConnectionString = this.SqlDatabaseContext.ServerConnectionString; - await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false); - IDbCommand command; - if (overwrite) - { - var drop = false; - using (command = dbConnection.CreateCommand()) - { - command.CommandText = "SELECT datname FROM pg_database;"; - using (var reader = (await command.ExecuteReaderExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false))) - { - while ((await reader.ReadExAsync(cancellationToken).ConfigureAwait(false))) - { - var s = reader.GetString(0); - if (s.Equals(databaseName)) - { - drop = true; - break; - } - } - } - } - - if (drop) - { - using (command = dbConnection.CreateCommand()) - { - command.CommandText = $"DROP DATABASE \"{databaseName}\";"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - } - - using (command = dbConnection.CreateCommand()) - { - command.CommandText = $"CREATE DATABASE \"{databaseName}\" WITH ENCODING 'UTF8';"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - retval = true; - } - else - { - try - { - using (command = dbConnection.CreateCommand()) - { - command.CommandText = $"CREATE DATABASE \"{databaseName}\" WITH ENCODING 'UTF8';"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - retval = true; - } - catch - { - retval = false; - } - } - } - - return retval; - } - } -} - -namespace Shaolinq.Postgres -{ -#pragma warning disable - using System; - using System.Data; - using System.Threading; - using System.Threading.Tasks; - using Npgsql; - using Platform; - using Shaolinq; - using NpgsqlTypes; - using Shaolinq.Postgres; - using Shaolinq.Persistence; - - public partial class PostgresSqlTransactionalCommandsContext - { - public override Task CommitAsync() - { - return this.CommitAsync(CancellationToken.None); - } - - public override async Task CommitAsync(CancellationToken cancellationToken) - { - if (this.preparedTransactionName != null) - { - using (var command = CreateCommand()) - { - command.CommandText = $"COMMIT PREPARED '{this.preparedTransactionName}';"; - await command.ExecuteNonQueryExAsync(this.DataAccessModel, cancellationToken).ConfigureAwait(false); - } - } - - await base.CommitAsync(cancellationToken).ConfigureAwait(false); - } - - public override Task RollbackAsync() - { - return this.RollbackAsync(CancellationToken.None); - } - - public override async Task RollbackAsync(CancellationToken cancellationToken) - { - if (this.preparedTransactionName != null) - { - using (var command = CreateCommand()) - { - command.CommandText = $"ROLLBACK PREPARED '{this.preparedTransactionName}';"; - await command.ExecuteNonQueryExAsync(this.DataAccessModel, cancellationToken).ConfigureAwait(false); - } - } - - await base.RollbackAsync(cancellationToken).ConfigureAwait(false); - } - } -} \ No newline at end of file diff --git a/src/Shaolinq.Postgres/RewriteAsyncAttribute.cs b/src/Shaolinq.Postgres/RewriteAsyncAttribute.cs deleted file mode 100644 index 9e9d48c4..00000000 --- a/src/Shaolinq.Postgres/RewriteAsyncAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - -using System; -using System.Reflection; - -namespace Shaolinq.Postgres -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] - public class RewriteAsyncAttribute - : Attribute - { - public bool ContinueOnCapturedContext { get; set; } - public MethodAttributes MethodAttributes { get; set; } - - public RewriteAsyncAttribute(MethodAttributes methodAttributes = default(MethodAttributes)) - { - this.MethodAttributes = methodAttributes; - } - } -} diff --git a/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj b/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj index 1d4fea0b..b874e9c5 100644 --- a/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj +++ b/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj @@ -13,5 +13,7 @@ - + + + diff --git a/src/Shaolinq.SqlServer/GeneratedAsync.cs b/src/Shaolinq.SqlServer/GeneratedAsync.cs deleted file mode 100644 index 24f2885a..00000000 --- a/src/Shaolinq.SqlServer/GeneratedAsync.cs +++ /dev/null @@ -1,97 +0,0 @@ -namespace Shaolinq.SqlServer -{ -#pragma warning disable - using System; - using System.Threading; - using System.Data.SqlClient; - using System.Threading.Tasks; - using System.Linq.Expressions; - using Shaolinq; - using Shaolinq.SqlServer; - using Shaolinq.Persistence; - - public partial class SqlServerSqlDatabaseSchemaManager - { - protected override Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options) - { - return this.CreateDatabaseOnlyAsync(dataDefinitionExpressions, options, CancellationToken.None); - } - - protected override async Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options, CancellationToken cancellationToken) - { - var factory = this.SqlDatabaseContext.CreateDbProviderFactory(); - var deleteDatabaseDropsTablesOnly = ((SqlServerSqlDatabaseContext)this.SqlDatabaseContext).DeleteDatabaseDropsTablesOnly; - using (var connection = factory.CreateConnection()) - { - if (connection == null) - { - throw new InvalidOperationException($"Unable to create connection from {factory}"); - } - - try - { - var databaseName = this.SqlDatabaseContext.DatabaseName.Trim(); - var context = (SqlServerSqlDatabaseContext)this.SqlDatabaseContext; - connection.ConnectionString = deleteDatabaseDropsTablesOnly ? this.SqlDatabaseContext.ConnectionString : this.SqlDatabaseContext.ServerConnectionString; - await connection.OpenAsync(cancellationToken).ConfigureAwait(false); - using (var command = (SqlCommand)connection.CreateCommand()) - { - if (options == DatabaseCreationOptions.DeleteExistingDatabase) - { - if (deleteDatabaseDropsTablesOnly) - { - command.CommandTimeout = Math.Min((int)(this.SqlDatabaseContext.CommandTimeout?.TotalSeconds ?? SqlDatabaseContextInfo.DefaultCommandTimeout), 300); - command.CommandText = @" - WHILE(exists(select 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='FOREIGN KEY')) - BEGIN - DECLARE @sql nvarchar(2000) - SELECT TOP 1 @sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']') - FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'FOREIGN KEY' - EXEC (@sql) - END - "; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - command.CommandText = @" - WHILE(exists(select 1 from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA != 'sys' AND TABLE_TYPE = 'BASE TABLE')) - BEGIN - declare @sql nvarchar(2000) - SELECT TOP 1 @sql=('DROP TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']') - FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA != 'sys' AND TABLE_TYPE = 'BASE TABLE' - EXEC (@sql) - END - "; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - command.CommandText = $"IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE NAME = '{databaseName}') CREATE DATABASE [{databaseName}];"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - else - { - command.CommandText = $"IF EXISTS (SELECT 1 FROM sys.databases WHERE NAME = '{databaseName}') DROP DATABASE [{databaseName}];"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - command.CommandText = $"CREATE DATABASE [{databaseName}];"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - } - else - { - command.CommandText = $"IF EXISTS (SELECT 1 FROM sys.databases WHERE NAME = '{databaseName}') DROP DATABASE [{databaseName}];"; - command.CommandText = $"CREATE DATABASE [{databaseName}];"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - command.CommandText = $"ALTER DATABASE [{databaseName}] SET ALLOW_SNAPSHOT_ISOLATION {(context.AllowSnapshotIsolation ? "ON" : "OFF")};"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - command.CommandText = $"ALTER DATABASE [{databaseName}] SET READ_COMMITTED_SNAPSHOT {(context.ReadCommittedSnapshot ? "ON" : "OFF")};"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - return true; - } - } - catch (Exception e) - { - Logger.Log(Logging.LogLevel.Error, () => "Exception creating database: " + e); - throw; - } - } - } - } -} \ No newline at end of file diff --git a/src/Shaolinq.SqlServer/RewriteAsyncAttribute.cs b/src/Shaolinq.SqlServer/RewriteAsyncAttribute.cs deleted file mode 100644 index 9a0441c1..00000000 --- a/src/Shaolinq.SqlServer/RewriteAsyncAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - -using System; -using System.Reflection; - -namespace Shaolinq.SqlServer -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] - internal class RewriteAsyncAttribute - : Attribute - { - public bool ContinueOnCapturedContext { get; } - public MethodAttributes MethodAttributes { get; } - - public RewriteAsyncAttribute(MethodAttributes methodAttributes = default(MethodAttributes), bool continueOnCapturedContext = false) - { - this.MethodAttributes = methodAttributes; - this.ContinueOnCapturedContext = continueOnCapturedContext; - } - } -} diff --git a/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj b/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj index f7f705ea..537462a0 100644 --- a/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj +++ b/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj @@ -13,5 +13,7 @@ - + + + diff --git a/src/Shaolinq.Sqlite/GeneratedAsync.cs b/src/Shaolinq.Sqlite/GeneratedAsync.cs deleted file mode 100644 index a78ad0ac..00000000 --- a/src/Shaolinq.Sqlite/GeneratedAsync.cs +++ /dev/null @@ -1,238 +0,0 @@ -namespace Shaolinq.Sqlite -{ -#pragma warning disable - using System; - using System.IO; - using System.Data; - using System.Threading; - using System.Threading.Tasks; - using System.Linq.Expressions; - using Shaolinq; - using Shaolinq.Sqlite; - using Shaolinq.Persistence; - - public abstract partial class SqliteSqlDatabaseSchemaManager - { - protected override Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options) - { - return this.CreateDatabaseOnlyAsync(dataDefinitionExpressions, options, CancellationToken.None); - } - - protected override async Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options, CancellationToken cancellationToken) - { - var retval = false; - var sqliteSqlDatabaseContext = (SqliteSqlDatabaseContext)this.SqlDatabaseContext; - var overwrite = options == DatabaseCreationOptions.DeleteExistingDatabase; - var path = sqliteSqlDatabaseContext.FileName; - if (sqliteSqlDatabaseContext.IsInMemoryConnection) - { - if (overwrite) - { - var connection = (await sqliteSqlDatabaseContext.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)); - if (sqliteSqlDatabaseContext.IsSharedCacheConnection) - { - // Keeping a reference around so that the in-memory DB survives - this.inMemoryConnection = (await sqliteSqlDatabaseContext.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)); - } - - using (var command = connection.CreateCommand()) - { - command.CommandText = @" - PRAGMA writable_schema = 1; - delete from sqlite_master where type = 'table'; - PRAGMA writable_schema = 0; - VACUUM; - "; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - } - - return true; - } - - if (overwrite) - { - try - { - File.Delete(path); - } - catch (FileNotFoundException) - { - } - catch (DirectoryNotFoundException) - { - } - - for (var i = 0; i < 2; i++) - { - try - { - CreateFile(path); - break; - } - catch (FileNotFoundException) - { - } - catch (DirectoryNotFoundException) - { - } - - var directoryPath = Path.GetDirectoryName(path); - if (!String.IsNullOrEmpty(directoryPath)) - { - try - { - Directory.CreateDirectory(directoryPath); - } - catch - { - } - } - } - - retval = true; - } - else - { - if (!File.Exists(path)) - { - for (var i = 0; i < 2; i++) - { - try - { - CreateFile(path); - break; - } - catch (FileNotFoundException) - { - } - catch (DirectoryNotFoundException) - { - } - - var directoryPath = Path.GetDirectoryName(path); - if (!String.IsNullOrEmpty(directoryPath)) - { - try - { - Directory.CreateDirectory(directoryPath); - } - catch - { - } - } - } - - retval = true; - } - else - { - retval = false; - } - } - - return retval; - } - } -} - -namespace Shaolinq.Sqlite -{ -#pragma warning disable - using System; - using System.IO; - using System.Data; - using System.Threading; - using System.Threading.Tasks; - using System.Text.RegularExpressions; - using Shaolinq; - using Shaolinq.Sqlite; - using Shaolinq.Persistence; - - public abstract partial class SqliteSqlDatabaseContext - { - public override Task OpenConnectionAsync() - { - return this.OpenConnectionAsync(CancellationToken.None); - } - - public override async Task OpenConnectionAsync(CancellationToken cancellationToken) - { - var retval = (await PrivateOpenConnectionAsync(cancellationToken).ConfigureAwait(false)); - if (retval == null) - { - return null; - } - - using (var command = retval.CreateCommand()) - { - command.CommandText = "PRAGMA foreign_keys = ON;"; - await command.ExecuteNonQueryExAsync(this.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - return retval; - } - - private Task PrivateOpenConnectionAsync() - { - return this.PrivateOpenConnectionAsync(CancellationToken.None); - } - - private async Task PrivateOpenConnectionAsync(CancellationToken cancellationToken) - { - if (!this.IsInMemoryConnection) - { - return (await base.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)); - } - - if (this.IsSharedCacheConnection) - { - return (await base.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)); - } - - return this.connection ?? (this.connection = new SqlitePersistentDbConnection((await base.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)))); - } - } -} - -namespace Shaolinq.Sqlite -{ -#pragma warning disable - using System; - using System.Data; - using System.Linq; - using System.Threading; - using System.Data.Common; - using System.Data.SQLite; - using System.Threading.Tasks; - using System.Collections.Generic; - using System.Text.RegularExpressions; - using Shaolinq; - using Shaolinq.Sqlite; - using Shaolinq.Logging; - using Shaolinq.Persistence; - - public partial class SqliteOfficialSqlDatabaseContext - { - public override Task BackupAsync(SqlDatabaseContext sqlDatabaseContext) - { - return this.BackupAsync(sqlDatabaseContext, CancellationToken.None); - } - - public override async Task BackupAsync(SqlDatabaseContext sqlDatabaseContext, CancellationToken cancellationToken) - { - if (!(sqlDatabaseContext is SqliteOfficialSqlDatabaseContext)) - { - throw new ArgumentException($"Needs to be a {nameof(SqliteOfficialSqlDatabaseContext)}", nameof(sqlDatabaseContext)); - } - - using (var connection = (await OpenConnectionAsync(cancellationToken).ConfigureAwait(false))) - { - using (var otherConnection = (await sqlDatabaseContext.OpenConnectionAsync(cancellationToken).ConfigureAwait(false))) - { - GetSqliteConnection(connection).BackupDatabase(GetSqliteConnection(otherConnection), "main", "main", -1, null, 1000); - } - } - } - } -} \ No newline at end of file diff --git a/src/Shaolinq.Sqlite/RewriteAsyncAttribute.cs b/src/Shaolinq.Sqlite/RewriteAsyncAttribute.cs deleted file mode 100644 index 8511f70b..00000000 --- a/src/Shaolinq.Sqlite/RewriteAsyncAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - -using System; -using System.Reflection; - -namespace Shaolinq.Sqlite -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] - internal class RewriteAsyncAttribute - : Attribute - { - public bool ContinueOnCapturedContext { get; } - public MethodAttributes MethodAttributes { get; } - - public RewriteAsyncAttribute(MethodAttributes methodAttributes = default(MethodAttributes), bool continueOnCapturedContext = false) - { - this.MethodAttributes = methodAttributes; - this.ContinueOnCapturedContext = continueOnCapturedContext; - } - } -} diff --git a/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj b/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj index 55c76595..4dd98efe 100644 --- a/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj +++ b/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj @@ -13,5 +13,7 @@ - + + + diff --git a/src/Shaolinq/Persistence/RewriteAsyncAttribute.cs b/src/Shaolinq/Persistence/RewriteAsyncAttribute.cs deleted file mode 100644 index d266b14f..00000000 --- a/src/Shaolinq/Persistence/RewriteAsyncAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - -using System; -using System.Reflection; - -namespace Shaolinq.Persistence -{ - [AttributeUsage(AttributeTargets.Method)] - internal class RewriteAsyncAttribute - : Attribute - { - public bool ContinueOnCapturedContext { get; } - public MethodAttributes MethodAttributes { get; } - - public RewriteAsyncAttribute(MethodAttributes methodAttributes = default(MethodAttributes), bool continueOnCapturedContext = false) - { - this.MethodAttributes = methodAttributes; - this.ContinueOnCapturedContext = continueOnCapturedContext; - } - } -} diff --git a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs index 35e47412..fb15a95c 100644 --- a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs +++ b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs @@ -4,7 +4,6 @@ namespace Shaolinq.AsyncRewriter.Sandbox public partial class Class1 { [RewriteAsync] - //[Shaolinq.AsyncRewriter.RewriteAsyncNext] public void Method() => Console.WriteLine("hello"); public int Value { get; set; } @@ -15,7 +14,7 @@ public class Class2 public async Task Method() { var xx = new Class1(); - //await xx.MethodAsync(); + await xx.MethodAsync(); } } } From 1696903aa7479e1eef753707c81f6b299a74d22f Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Wed, 22 Jun 2022 22:33:57 +0200 Subject: [PATCH 06/13] Pass RewriteAsync attribute to rewriter tests --- .../Generators/AsyncSourceGenerator.cs | 28 ++++++++++++++++--- .../Shaolinq.AsyncRewriter.Sandbox/Class1.cs | 5 ++++ .../AsyncRewriterTests.cs | 10 +++---- .../PrivateMethodsWithMethodAttributes.cs | 13 +++++++++ .../Shaolinq.AsyncRewriter.Tests.csproj | 1 + 5 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 tests/Shaolinq.AsyncRewriter.Tests/RewriteTests/PrivateMethodsWithMethodAttributes.cs diff --git a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs index d7348fff..a05a2b6b 100644 --- a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs @@ -1,6 +1,8 @@ using System; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; namespace Shaolinq.AsyncRewriter.Generators { @@ -16,12 +18,30 @@ public void Execute(GeneratorExecutionContext context) var r = new Rewriter(); try { - context.AddSource(AsyncRewriteAttributeClassGenerator.AttributeClassName, AsyncRewriteAttributeClassGenerator.SourceText(context.Compilation.AssemblyName.ToString())); + var rewriteAsyncAttribute = + AsyncRewriteAttributeClassGenerator.SourceText(context.Compilation.AssemblyName); - var syntaxTree = r.RewriteAndMerge(context.Compilation.SyntaxTrees, context.Compilation.References); + context.AddSource(AsyncRewriteAttributeClassGenerator.AttributeClassName, rewriteAsyncAttribute); + + var cSharpParseOptions = context.Compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions; + var options = CSharpParseOptions.Default.WithLanguageVersion(cSharpParseOptions?.LanguageVersion ?? LanguageVersion.CSharp8); - context.AddSource("GeneratedAsync", syntaxTree.ToString()); - } + var attributeSyntax = SyntaxFactory.ParseCompilationUnit( + rewriteAsyncAttribute.ToString(), 0, options) + .NormalizeWhitespace(); + + if (!Debugger.IsAttached) + { + //Debugger.Launch(); + } + + var syncVersion = SyntaxFactory.SyntaxTree(attributeSyntax, options); + context.Compilation.AddSyntaxTrees(syncVersion); + + var syntaxTree = r.RewriteAndMerge(context.Compilation.SyntaxTrees, context.Compilation.References); + + context.AddSource("GeneratedAsync", syntaxTree.ToString()); + } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); diff --git a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs index fb15a95c..c79a3731 100644 --- a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs +++ b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs @@ -1,4 +1,6 @@  +using System.Reflection; + namespace Shaolinq.AsyncRewriter.Sandbox { public partial class Class1 @@ -6,6 +8,9 @@ public partial class Class1 [RewriteAsync] public void Method() => Console.WriteLine("hello"); + [RewriteAsync(MethodAttributes.Private)] + private void PrivateMethod() => Console.WriteLine("private"); + public int Value { get; set; } } diff --git a/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs b/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs index c1ac53e7..423d9a93 100644 --- a/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs +++ b/tests/Shaolinq.AsyncRewriter.Tests/AsyncRewriterTests.cs @@ -37,11 +37,12 @@ private static IEnumerable GetTestCases() yield return GetTestCaseData("Nested async methods", "NestedAsync.cs"); yield return GetTestCaseData("Method resolution test", "MethodResolutionTest.cs"); yield return GetTestCaseData("Generic method call test", "GenericMethods.cs"); + yield return GetTestCaseData("Private method rewritten as public", "PrivateMethodsWithMethodAttributes.cs"); } private static TestCaseData GetTestCaseData(string name, params string[] inputFiles) { - return new TestCaseData(new object[] {inputFiles}).SetName(name); + return new TestCaseData(new object[] { inputFiles }).SetName(name); } [TestCaseSource(nameof(GetTestCases))] @@ -49,9 +50,9 @@ public void TestRewrite(params string[] inputFiles) { var rewriter = new Rewriter(); var root = Path.Combine(Path.GetDirectoryName(new Uri(GetType().Assembly.Location).LocalPath), "RewriteTests"); + var files = new List(inputFiles) {"RewriteAsyncAttribute.cs"}; + var result = rewriter.RewriteAndMerge(files.Select(c => Path.Combine(root, c)).ToArray()); - var result = rewriter.RewriteAndMerge(inputFiles.Select(c => Path.Combine(root, c)).ToArray()); - Assert.IsFalse(result.Contains(": N}\"")); Console.WriteLine(result); @@ -115,7 +116,7 @@ public void TestRewriteCompile(params string[] inputFiles) Console.Error.WriteLine(diagnostic); } - Assert.Fail(); + Assert.Fail(compileResult.Diagnostics.First().ToString()); } var assembly = Assembly.Load(ms.ToArray()); @@ -158,7 +159,6 @@ public void TestRewriteCompile(params string[] inputFiles) } } } - } } } diff --git a/tests/Shaolinq.AsyncRewriter.Tests/RewriteTests/PrivateMethodsWithMethodAttributes.cs b/tests/Shaolinq.AsyncRewriter.Tests/RewriteTests/PrivateMethodsWithMethodAttributes.cs new file mode 100644 index 00000000..71a82855 --- /dev/null +++ b/tests/Shaolinq.AsyncRewriter.Tests/RewriteTests/PrivateMethodsWithMethodAttributes.cs @@ -0,0 +1,13 @@ +using System.Reflection; + +namespace Shaolinq.AsyncRewriter.Tests.RewriteTests +{ + public partial class PrivateMethodsWithMethodAttributes + { + [RewriteAsync(MethodAttributes.Public)] + private int MyPrivateMethod(int parameter) + { + return 10 + parameter; + } + } +} \ No newline at end of file diff --git a/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj b/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj index b03efb56..6f11a969 100644 --- a/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj +++ b/tests/Shaolinq.AsyncRewriter.Tests/Shaolinq.AsyncRewriter.Tests.csproj @@ -19,6 +19,7 @@ + From a435e59fadcbce843fc8485ffffbb42bb253694f Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Sat, 25 Jun 2022 22:31:39 +0200 Subject: [PATCH 07/13] Place generated attribute into System namespace --- .../AsyncRewriteAttributeClassGenerator.cs | 66 ------------- ...nq.AsyncRewriter.AttributeGenerator.csproj | 12 --- .../AsyncRewriteAttributeClassGenerator.cs | 29 +----- .../Generators/AsyncSourceGenerator.cs | 31 +++---- .../Shaolinq.AsyncRewriter.target | 29 ------ .../MySqlSqlTransactionalCommandsContext.cs | 1 + .../GeneratedAsync.cs | 93 ------------------- .../Shaolinq.Postgres.DotConnect.csproj | 8 +- src/Shaolinq.Postgres.DotConnect/app.config | 72 +++++++------- .../PostgresSqlDatabaseSchemaManager.cs | 1 + src/Shaolinq.sln | 7 -- .../Persistence/DbCommandExtensions.cs | 1 + src/Shaolinq/Persistence/MarsDbCommand.cs | 1 + src/Shaolinq/Shaolinq.csproj | 9 -- .../Shaolinq.AsyncRewriter.Sandbox/Class1.cs | 2 +- 15 files changed, 61 insertions(+), 301 deletions(-) delete mode 100644 src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs delete mode 100644 src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj delete mode 100644 src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target delete mode 100644 src/Shaolinq.Postgres.DotConnect/GeneratedAsync.cs diff --git a/src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs b/src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs deleted file mode 100644 index 62f65a0e..00000000 --- a/src/Shaolinq.AsyncRewriter.AttributeGenerator/AsyncRewriteAttributeClassGenerator.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Diagnostics; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using System; - -namespace Shaolinq.AsyncRewriter.AttributeGenerator -{ - [Generator] - public class AsyncRewriteAttributeClassGenerator : ISourceGenerator - { - private const string AttributeClassName = "RewriteAsyncAttribute"; - - public static SourceText SourceText(string attributeNamespace, string app) => Microsoft.CodeAnalysis.Text.SourceText.From($@" -// Generated -using System; -using System.Reflection; - -namespace {attributeNamespace} -{{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] - public class RewriteAsyncAttribute{app} : Attribute - {{ - public RewriteAsyncAttribute{app}() - : this(default(MethodAttributes)) - {{ - }} - - public RewriteAsyncAttribute{app}(MethodAttributes methodAttributes) - {{ - this.MethodAttributes = methodAttributes; - }} - - public bool ContinueOnCapturedContext {{ get; set; }} - public bool ApplyToDescendents {{ get; set; }} - public MethodAttributes MethodAttributes {{ get; set; }} - }} -}} -// End -", Encoding.UTF8); - - public void Initialize(GeneratorInitializationContext context) - { - } - - public void Execute(GeneratorExecutionContext context) - { - if (!Debugger.IsAttached) - { - //Debugger.Launch(); - } - try - { - context.AddSource(AttributeClassName, SourceText(context.Compilation.AssemblyName.ToString(), "")); - context.AddSource("Another", SourceText(context.Compilation.AssemblyName.ToString(), "Two")); - context.AddSource("Three", SourceText(context.Compilation.AssemblyName.ToString(), "Three")); - } - catch (Exception ex) - { - Console.Error.WriteLine(ex.ToString()); - throw; - } - - } - } -} diff --git a/src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj b/src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj deleted file mode 100644 index f231b0ad..00000000 --- a/src/Shaolinq.AsyncRewriter.AttributeGenerator/Shaolinq.AsyncRewriter.AttributeGenerator.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - netstandard2.0 - - - - - - - - diff --git a/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs index 9623f140..db24a3a9 100644 --- a/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncRewriteAttributeClassGenerator.cs @@ -1,13 +1,10 @@ -using System.Diagnostics; using System.Text; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; -using System; + namespace Shaolinq.AsyncRewriter.Generators { - //[Generator] - public class AsyncRewriteAttributeClassGenerator //: ISourceGenerator + public class AsyncRewriteAttributeClassGenerator { public const string AttributeClassName = "RewriteAsyncAttribute"; @@ -38,28 +35,6 @@ public RewriteAsyncAttribute(MethodAttributes methodAttributes) }} // End ", Encoding.UTF8); - - public void Initialize(GeneratorInitializationContext context) - { - // context.RegisterForPostInitialization(ctx => ctx.AddSource("Attributes", StringConstants.Attributes)); - } - - public void Execute(GeneratorExecutionContext context) - { - if (!Debugger.IsAttached) - { - //Debugger.Launch(); - } - try - { - context.AddSource(AttributeClassName, SourceText(context.Compilation.AssemblyName.ToString())); - } - catch (Exception ex) - { - Console.Error.WriteLine(ex.ToString()); - throw; - } - } } } \ No newline at end of file diff --git a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs index a05a2b6b..e30ec12b 100644 --- a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs @@ -11,6 +11,13 @@ public class AsyncSourceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { + context.RegisterForPostInitialization(postInitContext => + { + var rewriteAsyncAttribute = + AsyncRewriteAttributeClassGenerator.SourceText("System"); + + postInitContext.AddSource(AsyncRewriteAttributeClassGenerator.AttributeClassName, rewriteAsyncAttribute); + }); } public void Execute(GeneratorExecutionContext context) @@ -18,25 +25,17 @@ public void Execute(GeneratorExecutionContext context) var r = new Rewriter(); try { - var rewriteAsyncAttribute = - AsyncRewriteAttributeClassGenerator.SourceText(context.Compilation.AssemblyName); - - context.AddSource(AsyncRewriteAttributeClassGenerator.AttributeClassName, rewriteAsyncAttribute); - var cSharpParseOptions = context.Compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions; - var options = CSharpParseOptions.Default.WithLanguageVersion(cSharpParseOptions?.LanguageVersion ?? LanguageVersion.CSharp8); - - var attributeSyntax = SyntaxFactory.ParseCompilationUnit( - rewriteAsyncAttribute.ToString(), 0, options) - .NormalizeWhitespace(); + + //var cSharpParseOptions = context.Compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions; + //var options = CSharpParseOptions.Default.WithLanguageVersion(cSharpParseOptions?.LanguageVersion ?? LanguageVersion.CSharp8); - if (!Debugger.IsAttached) - { - //Debugger.Launch(); - } + //var attributeSyntax = SyntaxFactory.ParseCompilationUnit( + // rewriteAsyncAttribute.ToString(), 0, options) + //// .NormalizeWhitespace(); - var syncVersion = SyntaxFactory.SyntaxTree(attributeSyntax, options); - context.Compilation.AddSyntaxTrees(syncVersion); + //var syncVersion = SyntaxFactory.SyntaxTree(attributeSyntax, options); + // context.Compilation.AddSyntaxTrees(syncVersion); var syntaxTree = r.RewriteAndMerge(context.Compilation.SyntaxTrees, context.Compilation.References); diff --git a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target deleted file mode 100644 index e0046e59..00000000 --- a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.target +++ /dev/null @@ -1,29 +0,0 @@ - - - - "..\Shaolinq.AsyncRewriter\bin\$(Configuration)\net6.0\Shaolinq.AsyncRewriter.exe" - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Shaolinq.MySql/MySqlSqlTransactionalCommandsContext.cs b/src/Shaolinq.MySql/MySqlSqlTransactionalCommandsContext.cs index 97603503..8f2e09d3 100644 --- a/src/Shaolinq.MySql/MySqlSqlTransactionalCommandsContext.cs +++ b/src/Shaolinq.MySql/MySqlSqlTransactionalCommandsContext.cs @@ -1,5 +1,6 @@ // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) +using System; using System.Data; using System.Linq.Expressions; using Shaolinq.Persistence; diff --git a/src/Shaolinq.Postgres.DotConnect/GeneratedAsync.cs b/src/Shaolinq.Postgres.DotConnect/GeneratedAsync.cs deleted file mode 100644 index 5b70c045..00000000 --- a/src/Shaolinq.Postgres.DotConnect/GeneratedAsync.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Shaolinq.Postgres -{ -#pragma warning disable - using System; - // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) - using System.Data; - using System.Threading; - using System.Threading.Tasks; - using System.Linq.Expressions; - using Shaolinq; - using Shaolinq.Postgres; - using Shaolinq.Persistence; - using Shaolinq.Persistence.Linq; - - public partial class PostgresSqlDatabaseSchemaManager - { - protected override Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options) - { - return this.CreateDatabaseOnlyAsync(dataDefinitionExpressions, options, CancellationToken.None); - } - - protected override async Task CreateDatabaseOnlyAsync(Expression dataDefinitionExpressions, DatabaseCreationOptions options, CancellationToken cancellationToken) - { - var retval = false; - var factory = this.SqlDatabaseContext.CreateDbProviderFactory(); - var databaseName = this.SqlDatabaseContext.DatabaseName; - var overwrite = options == DatabaseCreationOptions.DeleteExistingDatabase; - this.SqlDatabaseContext.DropAllConnections(); - using (var dbConnection = factory.CreateConnection()) - { - dbConnection.ConnectionString = this.SqlDatabaseContext.ServerConnectionString; - await dbConnection.OpenAsync(cancellationToken).ConfigureAwait(false); - IDbCommand command; - if (overwrite) - { - var drop = false; - using (command = dbConnection.CreateCommand()) - { - command.CommandText = "SELECT datname FROM pg_database;"; - using (var reader = (await command.ExecuteReaderExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false))) - { - while ((await reader.ReadExAsync(cancellationToken).ConfigureAwait(false))) - { - var s = reader.GetString(0); - if (s.Equals(databaseName)) - { - drop = true; - break; - } - } - } - } - - if (drop) - { - using (command = dbConnection.CreateCommand()) - { - command.CommandText = $"DROP DATABASE \"{databaseName}\";"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - } - - using (command = dbConnection.CreateCommand()) - { - command.CommandText = $"CREATE DATABASE \"{databaseName}\" WITH ENCODING 'UTF8';"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - retval = true; - } - else - { - try - { - using (command = dbConnection.CreateCommand()) - { - command.CommandText = $"CREATE DATABASE \"{databaseName}\" WITH ENCODING 'UTF8';"; - await command.ExecuteNonQueryExAsync(this.SqlDatabaseContext.DataAccessModel, cancellationToken, true).ConfigureAwait(false); - } - - retval = true; - } - catch - { - retval = false; - } - } - } - - return retval; - } - } -} \ No newline at end of file diff --git a/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj b/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj index 9eeae922..b23b2511 100644 --- a/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj +++ b/src/Shaolinq.Postgres.DotConnect/Shaolinq.Postgres.DotConnect.csproj @@ -168,10 +168,6 @@ PostgresUuidSqlDataType.cs - - RewriteAsyncAttribute.cs - - @@ -210,7 +206,9 @@ + + + - \ No newline at end of file diff --git a/src/Shaolinq.Postgres.DotConnect/app.config b/src/Shaolinq.Postgres.DotConnect/app.config index 4153bcf3..4dadb009 100644 --- a/src/Shaolinq.Postgres.DotConnect/app.config +++ b/src/Shaolinq.Postgres.DotConnect/app.config @@ -1,76 +1,76 @@ - + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/src/Shaolinq.Postgres/PostgresSqlDatabaseSchemaManager.cs b/src/Shaolinq.Postgres/PostgresSqlDatabaseSchemaManager.cs index fcc3e549..0d3c7a6f 100644 --- a/src/Shaolinq.Postgres/PostgresSqlDatabaseSchemaManager.cs +++ b/src/Shaolinq.Postgres/PostgresSqlDatabaseSchemaManager.cs @@ -1,5 +1,6 @@ // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) +using System; using System.Data; using System.Linq.Expressions; using Shaolinq.Persistence; diff --git a/src/Shaolinq.sln b/src/Shaolinq.sln index 5722aa0f..96d3c7f5 100644 --- a/src/Shaolinq.sln +++ b/src/Shaolinq.sln @@ -56,8 +56,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.ExpressionWriter.T EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shaolinq.AsyncRewriter.Sandbox", "..\tests\Shaolinq.AsyncRewriter.Sandbox\Shaolinq.AsyncRewriter.Sandbox.csproj", "{3F73A8AD-6F5A-4218-8BC9-CCB241137747}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shaolinq.AsyncRewriter.AttributeGenerator", "Shaolinq.AsyncRewriter.AttributeGenerator\Shaolinq.AsyncRewriter.AttributeGenerator.csproj", "{46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -124,10 +122,6 @@ Global {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Debug|Any CPU.Build.0 = Debug|Any CPU {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F73A8AD-6F5A-4218-8BC9-CCB241137747}.Release|Any CPU.Build.0 = Release|Any CPU - {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -140,7 +134,6 @@ Global {F0CE5F64-52A9-405B-BCD0-ACEB6CF43B41} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} {3725382B-D77B-431F-B51B-7FDFB9687F4B} = {C91EDDBA-2D1C-478A-84C8-88A7523B88B8} {3F73A8AD-6F5A-4218-8BC9-CCB241137747} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} - {46D8581D-3BDF-4BC0-B7C7-2A9639F48CF7} = {BB073B54-12FA-498C-A94A-9D154F4D00EE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6F0187C2-422B-42D1-A61E-1A265A4DE8CE} diff --git a/src/Shaolinq/Persistence/DbCommandExtensions.cs b/src/Shaolinq/Persistence/DbCommandExtensions.cs index b3a4706d..ba6709eb 100644 --- a/src/Shaolinq/Persistence/DbCommandExtensions.cs +++ b/src/Shaolinq/Persistence/DbCommandExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) +using System; using System.Data; using System.Data.Common; diff --git a/src/Shaolinq/Persistence/MarsDbCommand.cs b/src/Shaolinq/Persistence/MarsDbCommand.cs index 1b601440..2f827514 100644 --- a/src/Shaolinq/Persistence/MarsDbCommand.cs +++ b/src/Shaolinq/Persistence/MarsDbCommand.cs @@ -1,5 +1,6 @@ // Copyright (c) 2007-2018 Thong Nguyen (tumtumtum@gmail.com) +using System; using System.Data; using System.Data.Common; diff --git a/src/Shaolinq/Shaolinq.csproj b/src/Shaolinq/Shaolinq.csproj index 8fa52b9f..b3f7670d 100644 --- a/src/Shaolinq/Shaolinq.csproj +++ b/src/Shaolinq/Shaolinq.csproj @@ -6,17 +6,8 @@ Shaolinq TRACE;LIBLOG_PUBLIC true - - - - - all diff --git a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs index c79a3731..db32cddb 100644 --- a/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs +++ b/tests/Shaolinq.AsyncRewriter.Sandbox/Class1.cs @@ -8,7 +8,7 @@ public partial class Class1 [RewriteAsync] public void Method() => Console.WriteLine("hello"); - [RewriteAsync(MethodAttributes.Private)] + [RewriteAsync(MethodAttributes.Public)] private void PrivateMethod() => Console.WriteLine("private"); public int Value { get; set; } From edbad22a47f702b2a93296620855c030be4e2fc8 Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Sun, 26 Jun 2022 10:46:42 +0200 Subject: [PATCH 08/13] Complete conversion of Expression writer and hasher --- .../Generators/AsyncSourceGenerator.cs | 12 --------- .../ExpressionComparerWriter.cs | 23 ++++++++++++++--- .../ExpressionHasherWriter.cs | 25 +++++++++++++++---- .../ExpressionWriterSourceGenerator.cs | 4 ++- .../Shaolinq.ExpressionWriter.csproj | 21 ++++++++++------ src/Shaolinq/Shaolinq.csproj | 10 -------- 6 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs index e30ec12b..93ed0ce7 100644 --- a/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs +++ b/src/Shaolinq.AsyncRewriter/Generators/AsyncSourceGenerator.cs @@ -25,18 +25,6 @@ public void Execute(GeneratorExecutionContext context) var r = new Rewriter(); try { - - - //var cSharpParseOptions = context.Compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions; - //var options = CSharpParseOptions.Default.WithLanguageVersion(cSharpParseOptions?.LanguageVersion ?? LanguageVersion.CSharp8); - - //var attributeSyntax = SyntaxFactory.ParseCompilationUnit( - // rewriteAsyncAttribute.ToString(), 0, options) - //// .NormalizeWhitespace(); - - //var syncVersion = SyntaxFactory.SyntaxTree(attributeSyntax, options); - // context.Compilation.AddSyntaxTrees(syncVersion); - var syntaxTree = r.RewriteAndMerge(context.Compilation.SyntaxTrees, context.Compilation.References); context.AddSource("GeneratedAsync", syntaxTree.ToString()); diff --git a/src/Shaolinq.ExpressionWriter/ExpressionComparerWriter.cs b/src/Shaolinq.ExpressionWriter/ExpressionComparerWriter.cs index 9f03ddc4..3abb4984 100644 --- a/src/Shaolinq.ExpressionWriter/ExpressionComparerWriter.cs +++ b/src/Shaolinq.ExpressionWriter/ExpressionComparerWriter.cs @@ -14,13 +14,19 @@ namespace Shaolinq.ExpressionWriter public class ExpressionComparerWriter { private readonly string[] paths; + private IEnumerable syntaxTrees; - private ExpressionComparerWriter(string[] paths) + private ExpressionComparerWriter(string[] paths) { this.paths = paths; } - - private IEnumerable GetProperties(INamedTypeSymbol type,bool inherited = true) + + public ExpressionComparerWriter(IEnumerable syntaxTrees) + { + this.syntaxTrees = syntaxTrees; + } + + private IEnumerable GetProperties(INamedTypeSymbol type,bool inherited = true) { return GetProperties(type, new HashSet(), inherited); } @@ -213,7 +219,11 @@ private BlockSyntax CreateMethodBody(SemanticModel model, INamedTypeSymbol typeS private string Write() { - var syntaxTrees = this.paths.Select(p => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(p))).ToList(); + if(syntaxTrees == null) + { + syntaxTrees = this.paths.Select(p => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(p))).ToList(); + } + var compilation = CSharpCompilation.Create("Temp", syntaxTrees, null, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences ( @@ -285,6 +295,11 @@ private string Write() return result.ToString(); } + internal static string Write(IEnumerable syntaxTrees) + { + return new ExpressionComparerWriter(syntaxTrees).Write(); + } + public static string Write(string[] sourcePaths) { return new ExpressionComparerWriter(sourcePaths).Write(); diff --git a/src/Shaolinq.ExpressionWriter/ExpressionHasherWriter.cs b/src/Shaolinq.ExpressionWriter/ExpressionHasherWriter.cs index 96832713..fdeb8d32 100644 --- a/src/Shaolinq.ExpressionWriter/ExpressionHasherWriter.cs +++ b/src/Shaolinq.ExpressionWriter/ExpressionHasherWriter.cs @@ -13,18 +13,24 @@ namespace Shaolinq.ExpressionWriter public class ExpressionHasherWriter { private readonly string[] paths; + private IEnumerable syntaxTrees; - private ExpressionHasherWriter(string[] paths) + private ExpressionHasherWriter(string[] paths) { this.paths = paths; } - - private IEnumerable GetProperties(INamedTypeSymbol type,bool inherited = true) + + public ExpressionHasherWriter(IEnumerable syntaxTrees) + { + this.syntaxTrees = syntaxTrees; + } + + private IEnumerable GetProperties(INamedTypeSymbol type,bool inherited = true) { return GetProperties(type, new HashSet(), inherited); } - private IEnumerable GetProperties(INamedTypeSymbol type, HashSet alreadyAdded, bool inherited = true) + private IEnumerable GetProperties(INamedTypeSymbol type, HashSet alreadyAdded, bool inherited = true) { foreach (var member in type.GetMembers()) { @@ -140,7 +146,11 @@ private BlockSyntax CreateMethodBody(SemanticModel model, INamedTypeSymbol typeS private string Write() { - var syntaxTrees = this.paths.Select(p => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(p))).ToList(); + if(syntaxTrees == null) + { + syntaxTrees = this.paths.Select(p => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(p))).ToList(); + } + var compilation = CSharpCompilation.Create("Temp", syntaxTrees, null, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences ( @@ -218,6 +228,11 @@ private string Write() return result.ToString(); } + internal static string Write(IEnumerable syntaxTrees) + { + return new ExpressionHasherWriter(syntaxTrees).Write(); + } + public static string Write(string[] sourcePaths) { return new ExpressionHasherWriter(sourcePaths).Write(); diff --git a/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs b/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs index 30618c72..23a7145c 100644 --- a/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs +++ b/src/Shaolinq.ExpressionWriter/Generators/ExpressionWriterSourceGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using Microsoft.CodeAnalysis; namespace Shaolinq.ExpressionWriter.Generators @@ -14,7 +15,8 @@ public void Execute(GeneratorExecutionContext context) { try { - + context.AddSource("GeneratedSqlExpressionComparer", ExpressionComparerWriter.Write(context.Compilation.SyntaxTrees)); + context.AddSource("GeneratedSqlExpressionHasher", ExpressionHasherWriter.Write(context.Compilation.SyntaxTrees)); } catch (Exception ex) { diff --git a/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj b/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj index 0638c9cc..51628bb9 100644 --- a/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj +++ b/src/Shaolinq.ExpressionWriter/Shaolinq.ExpressionWriter.csproj @@ -1,4 +1,4 @@ - + Shaolinq.ExpressionWriter @@ -7,12 +7,19 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + + + + $(GetTargetPathDependsOn);GetDependencyTargetPaths + + + + + + diff --git a/src/Shaolinq/Shaolinq.csproj b/src/Shaolinq/Shaolinq.csproj index b3f7670d..016cdeb1 100644 --- a/src/Shaolinq/Shaolinq.csproj +++ b/src/Shaolinq/Shaolinq.csproj @@ -19,16 +19,6 @@ - - - - - - - - - - From 0df78ebfca9f2cf00697314bd1d91f385d82a6be Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Mon, 27 Jun 2022 22:08:56 +0200 Subject: [PATCH 09/13] Remove unused nuspec files and use csproj properties instead --- nuspec/GeneratedAsync.cs.pp | 0 nuspec/RewriteAsyncAttribute.cs.pp | 26 -------------- nuspec/Shaolinq.AsyncRewriter.nuspec | 22 ------------ nuspec/Shaolinq.AsyncRewriter.props | 4 --- nuspec/Shaolinq.AsyncRewriter.targets | 25 ------------- nuspec/Shaolinq.MySql.nuspec | 36 ------------------- nuspec/Shaolinq.Postgres.DotConnect.nuspec | 2 +- nuspec/Shaolinq.Postgres.nuspec | 36 ------------------- nuspec/Shaolinq.SqlServer.nuspec | 35 ------------------ nuspec/Shaolinq.Sqlite.nuspec | 36 ------------------- nuspec/Shaolinq.nuspec | 34 ------------------ .../Shaolinq.AsyncRewriter.csproj | 17 ++++++--- src/Shaolinq.MySql/Shaolinq.MySql.csproj | 29 +++++++++++++++ .../Shaolinq.Postgres.csproj | 29 +++++++++++++++ .../Shaolinq.SqlServer.csproj | 29 +++++++++++++++ src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj | 29 +++++++++++++++ src/Shaolinq/Shaolinq.csproj | 27 ++++++++++++++ 17 files changed, 157 insertions(+), 259 deletions(-) delete mode 100644 nuspec/GeneratedAsync.cs.pp delete mode 100644 nuspec/RewriteAsyncAttribute.cs.pp delete mode 100644 nuspec/Shaolinq.AsyncRewriter.nuspec delete mode 100644 nuspec/Shaolinq.AsyncRewriter.props delete mode 100644 nuspec/Shaolinq.AsyncRewriter.targets delete mode 100644 nuspec/Shaolinq.MySql.nuspec delete mode 100644 nuspec/Shaolinq.Postgres.nuspec delete mode 100644 nuspec/Shaolinq.SqlServer.nuspec delete mode 100644 nuspec/Shaolinq.Sqlite.nuspec delete mode 100644 nuspec/Shaolinq.nuspec diff --git a/nuspec/GeneratedAsync.cs.pp b/nuspec/GeneratedAsync.cs.pp deleted file mode 100644 index e69de29b..00000000 diff --git a/nuspec/RewriteAsyncAttribute.cs.pp b/nuspec/RewriteAsyncAttribute.cs.pp deleted file mode 100644 index 3e661d0a..00000000 --- a/nuspec/RewriteAsyncAttribute.cs.pp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2016 Thong Nguyen (tumtumtum@gmail.com) - -using System; -using System.Reflection; - -namespace $rootnamespace$ -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] - internal class RewriteAsyncAttribute - : Attribute - { - public bool ContinueOnCapturedContext { get; set; } - public MethodAttributes MethodAttributes { get; set; } - public bool ApplyToDescendents {get; set; } - - public RewriteAsyncAttribute() - : this(default(MethodAttributes)) - { - } - - public RewriteAsyncAttribute(MethodAttributes methodAttributes) - { - this.MethodAttributes = methodAttributes; - } - } -} diff --git a/nuspec/Shaolinq.AsyncRewriter.nuspec b/nuspec/Shaolinq.AsyncRewriter.nuspec deleted file mode 100644 index 37fb884e..00000000 --- a/nuspec/Shaolinq.AsyncRewriter.nuspec +++ /dev/null @@ -1,22 +0,0 @@ - - - - Shaolinq.AsyncRewriter - $version$ - Shaolinq AsyncRewriter - Automatically generates async versions of your methods - true - Thong Nguyen - Thong Nguyen - https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt - https://github.com/tumtumtum/Shaolinq - false - -Stop copying and pasting code in order to support Async/Await! Shaolinq.AsyncRewriter generates async methods from your sync methods using Roslyn. -AsyncRewriter is used extensively by the Shaolinq ORM/LINQ project. - - $releasenotes$ - Copyright (c) 2016-2018 Thong Nguyen (tumtumtum@gmail.com) - shaolinq async rewriter asyncrewriter await codegen roslyn - - \ No newline at end of file diff --git a/nuspec/Shaolinq.AsyncRewriter.props b/nuspec/Shaolinq.AsyncRewriter.props deleted file mode 100644 index 2425f6fe..00000000 --- a/nuspec/Shaolinq.AsyncRewriter.props +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/nuspec/Shaolinq.AsyncRewriter.targets b/nuspec/Shaolinq.AsyncRewriter.targets deleted file mode 100644 index bc402bc9..00000000 --- a/nuspec/Shaolinq.AsyncRewriter.targets +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - @(Compile) - GeneratedAsync.cs - $(BaseIntermediateOutputPath)\$(Configuration)\GeneratedAsync.cs - - - - False - - - - - - - - - - \ No newline at end of file diff --git a/nuspec/Shaolinq.MySql.nuspec b/nuspec/Shaolinq.MySql.nuspec deleted file mode 100644 index e6c52611..00000000 --- a/nuspec/Shaolinq.MySql.nuspec +++ /dev/null @@ -1,36 +0,0 @@ - - - - Shaolinq.MySql - $version$ - Shaolinq ORM and Linq provider for MySql - A thoughtful ORM and Linq provider for .NET and MySql - Thong Nguyen - Thong Nguyen - https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt - https://github.com/tumtumtum/Shaolinq - false - Shaolinq is a thoughtfully designed ORM and Linq provider for .NET - -Use this package to add Shaolinq and out-of-the-box MySql support. - -Designed to perform super fast and be easy to use, Shaolinq's features also include: - -- First class schema-first ORM with WYSIWYG data access and minipulation. -- First class LINQ support (not the basic kind you see in most other OSS projects). -- Single trip updating of objects. -- Support for Sqlite, MySql and Postgres. -- Automatic database creation and schema migration. -- Delete LINQ extension for batch server side deletes. -- Full support for server side date functions (Date.DayOfWeek etc). -- Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. -- Open Source! - $releasenotes$ - Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) - shaolinq linq provider orm sqlite mysql sql database - - - - - - \ No newline at end of file diff --git a/nuspec/Shaolinq.Postgres.DotConnect.nuspec b/nuspec/Shaolinq.Postgres.DotConnect.nuspec index 0c77c48a..2c1f9e6f 100644 --- a/nuspec/Shaolinq.Postgres.DotConnect.nuspec +++ b/nuspec/Shaolinq.Postgres.DotConnect.nuspec @@ -30,7 +30,7 @@ Designed to perform super fast and be easy to use, Shaolinq's features also incl shaolinq linq provider orm postgres sql database - + \ No newline at end of file diff --git a/nuspec/Shaolinq.Postgres.nuspec b/nuspec/Shaolinq.Postgres.nuspec deleted file mode 100644 index 4a70ade8..00000000 --- a/nuspec/Shaolinq.Postgres.nuspec +++ /dev/null @@ -1,36 +0,0 @@ - - - - Shaolinq.Postgres - $version$ - Shaolinq ORM and Linq provider for Postgres - A thoughtful ORM and Linq provider for .NET and Postgres - Thong Nguyen - Thong Nguyen - https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt - https://github.com/tumtumtum/Shaolinq - false - Shaolinq is a thoughtfully designed ORM and Linq provider for .NET - -Use this package to add Shaolinq and out-of-the-box Postgres support (via Npgsql). - -Designed to perform super fast and be easy to use, Shaolinq's features also include: - -- First class schema-first ORM with WYSIWYG data access and minipulation. -- First class LINQ support (not the basic kind you see in most other OSS projects). -- Single trip updating of objects. -- Support for Sqlite, MySql and Postgres. -- Automatic database creation and schema migration. -- Delete LINQ extension for batch server side deletes. -- Full support for server side date functions (Date.DayOfWeek etc). -- Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. -- Open Source! - $releasenotes$ - Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) - shaolinq linq provider orm postgres sql database - - - - - - \ No newline at end of file diff --git a/nuspec/Shaolinq.SqlServer.nuspec b/nuspec/Shaolinq.SqlServer.nuspec deleted file mode 100644 index 9ebdbacb..00000000 --- a/nuspec/Shaolinq.SqlServer.nuspec +++ /dev/null @@ -1,35 +0,0 @@ - - - - Shaolinq.SqlServer - $version$ - Shaolinq ORM and Linq provider for SQL Server - A thoughtful ORM and Linq provider for .NET and SQL Server - Thong Nguyen - Thong Nguyen - https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt - https://github.com/tumtumtum/Shaolinq - false - Shaolinq is a thoughtfully designed ORM and Linq provider for .NET - -Use this package to add Shaolinq and out-of-the-box MySql support. - -Designed to perform super fast and be easy to use, Shaolinq's features also include: - -- First class schema-first ORM with WYSIWYG data access and minipulation. -- First class LINQ support (not the basic kind you see in most other OSS projects). -- Single trip updating of objects. -- Support for Sqlite, MySql, Postgres and SQL Server. -- Automatic database creation and schema migration. -- Delete LINQ extension for batch server side deletes. -- Full support for server side date functions (Date.DayOfWeek etc). -- Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. -- Open Source! - $releasenotes$ - Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) - shaolinq linq provider orm sqlite mysql sql database - - - - - \ No newline at end of file diff --git a/nuspec/Shaolinq.Sqlite.nuspec b/nuspec/Shaolinq.Sqlite.nuspec deleted file mode 100644 index a23a8fa3..00000000 --- a/nuspec/Shaolinq.Sqlite.nuspec +++ /dev/null @@ -1,36 +0,0 @@ - - - - Shaolinq.Sqlite - $version$ - Shaolinq ORM and Linq provider for Sqlite - A thoughtful ORM and Linq provider for .NET and Sqlite - Thong Nguyen - Thong Nguyen - https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt - https://github.com/tumtumtum/Shaolinq - false - Shaolinq is a thoughtfully designed ORM and Linq provider for .NET - -Use this package to add Shaolinq and out-of-the-box Sqlite support. - -Designed to perform super fast and be easy to use, Shaolinq's features also include: - -- First class schema-first ORM with WYSIWYG data access and minipulation. -- First class LINQ support (not the basic kind you see in most other OSS projects). -- Single trip updating of objects. -- Support for Sqlite, MySql and Postgres. -- Automatic database creation and schema migration. -- Delete LINQ extension for batch server side deletes. -- Full support for server side date functions (Date.DayOfWeek etc). -- Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. -- Open Source! - $releasenotes$ - Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) - shaolinq linq provider orm sqlite sql database - - - - - - \ No newline at end of file diff --git a/nuspec/Shaolinq.nuspec b/nuspec/Shaolinq.nuspec deleted file mode 100644 index 3c5c50b4..00000000 --- a/nuspec/Shaolinq.nuspec +++ /dev/null @@ -1,34 +0,0 @@ - - - - Shaolinq - $version$ - Shaolinq ORM and Linq provider - A thoughtful ORM and Linq provider for .NET - Thong Nguyen - Thong Nguyen - https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt - https://github.com/tumtumtum/Shaolinq - false - Shaolinq is a thoughtfully designed ORM and Linq provider for .NET - -Designed to perform super fast and be easy to use, Shaolinq's features also include: - -- First class schema-first ORM with WYSIWYG data access and minipulation. -- First class LINQ support (not the basic kind you see in most other OSS projects). -- Single trip updating of objects. -- Support for Sqlite, MySql and Postgres. -- Automatic database creation and schema migration. -- Delete LINQ extension for batch server side deletes. -- Full support for server side date functions (Date.DayOfWeek etc). -- Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. -- Open Source! - $releasenotes$ - Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) - shaolinq linq provider orm sqlite mysql postgres sql database - - - - - - \ No newline at end of file diff --git a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj index e01814a7..bca02155 100644 --- a/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj +++ b/src/Shaolinq.AsyncRewriter/Shaolinq.AsyncRewriter.csproj @@ -1,20 +1,29 @@  - netstandard2.0 - 3.0.15-anton + netstandard2.0 Shaolinq.AsyncRewriter Shaolinq.AsyncRewriter false + + + latestmajor + + Shaolinq.AsyncRewriter + 2.0.0 Shaolinq AsyncRewriter + Thong Nguyen + https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt + https://github.com/tumtumtum/Shaolinq + false Stop copying and pasting code in order to support Async/Await! Shaolinq.AsyncRewriter generates async methods from your sync methods using Roslyn. AsyncRewriter is used extensively by the Shaolinq ORM/LINQ project. + $releasenotes$ + Copyright (c) 2016-2022 Thong Nguyen (tumtumtum@gmail.com) shaolinq async rewriter asyncrewriter await codegen roslyn - latestmajor - false diff --git a/src/Shaolinq.MySql/Shaolinq.MySql.csproj b/src/Shaolinq.MySql/Shaolinq.MySql.csproj index 885da343..62c3dc55 100644 --- a/src/Shaolinq.MySql/Shaolinq.MySql.csproj +++ b/src/Shaolinq.MySql/Shaolinq.MySql.csproj @@ -4,6 +4,35 @@ netstandard2.0 Shaolinq.MySql Shaolinq.MySql + + + Shaolinq.MySql + 2.0.0 + Shaolinq ORM and Linq provider for MySql + Thong Nguyen + Thong Nguyen + https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt + https://github.com/tumtumtum/Shaolinq + false + Shaolinq is a thoughtfully designed ORM and Linq provider for .NET + +Use this package to add Shaolinq and out-of-the-box MySql support. + +Designed to perform super fast and be easy to use, Shaolinq's features also include: + +- First class schema-first ORM with WYSIWYG data access and minipulation. +- First class LINQ support (not the basic kind you see in most other OSS projects). +- Single trip updating of objects. +- Support for Sqlite, MySql and Postgres. +- Automatic database creation and schema migration. +- Delete LINQ extension for batch server side deletes. +- Full support for server side date functions (Date.DayOfWeek etc). +- Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. +- Open Source! + + $releasenotes$ + Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) + shaolinq linq provider orm sqlite mysql sql database diff --git a/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj b/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj index b874e9c5..54f4798c 100644 --- a/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj +++ b/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj @@ -4,6 +4,35 @@ netstandard2.0 Shaolinq.Postgres Shaolinq.Postgres + + + Shaolinq.Postgres + 2.0.0 + Shaolinq ORM and Linq provider for Postgres + Thong Nguyen + https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt + https://github.com/tumtumtum/Shaolinq + false + + Shaolinq is a thoughtfully designed ORM and Linq provider for .NET + + Use this package to add Shaolinq and out-of-the-box Postgres support (via Npgsql). + + Designed to perform super fast and be easy to use, Shaolinq's features also include: + + - First class schema-first ORM with WYSIWYG data access and minipulation. + - First class LINQ support (not the basic kind you see in most other OSS projects). + - Single trip updating of objects. + - Support for Sqlite, MySql and Postgres. + - Automatic database creation and schema migration. + - Delete LINQ extension for batch server side deletes. + - Full support for server side date functions (Date.DayOfWeek etc). + - Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. + - Open Source! + + $releasenotes$ + Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) + shaolinq linq provider orm postgres sql database diff --git a/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj b/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj index 537462a0..422ac8d3 100644 --- a/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj +++ b/src/Shaolinq.SqlServer/Shaolinq.SqlServer.csproj @@ -4,6 +4,35 @@ netstandard2.0 Shaolinq.SqlServer Shaolinq.SqlServer + + + Shaolinq.SqlServer + 2.0.0 + Shaolinq ORM and Linq provider for SQL Server + Thong Nguyen + https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt + https://github.com/tumtumtum/Shaolinq + false + + Shaolinq is a thoughtfully designed ORM and Linq provider for .NET + + Use this package to add Shaolinq and out-of-the-box MySql support. + + Designed to perform super fast and be easy to use, Shaolinq's features also include: + + - First class schema-first ORM with WYSIWYG data access and minipulation. + - First class LINQ support (not the basic kind you see in most other OSS projects). + - Single trip updating of objects. + - Support for Sqlite, MySql, Postgres and SQL Server. + - Automatic database creation and schema migration. + - Delete LINQ extension for batch server side deletes. + - Full support for server side date functions (Date.DayOfWeek etc). + - Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. + - Open Source! + + $releasenotes$ + Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) + shaolinq linq provider orm sqlite mysql sql database diff --git a/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj b/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj index 4dd98efe..dade2302 100644 --- a/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj +++ b/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj @@ -4,6 +4,35 @@ netstandard2.0 Shaolinq.Sqlite Shaolinq.Sqlite + + + Shaolinq.Sqlite + 2.0.0 + Shaolinq ORM and Linq provider for Sqlite + Thong Nguyen + https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt + https://github.com/tumtumtum/Shaolinq + false + + Shaolinq is a thoughtfully designed ORM and Linq provider for .NET + + Use this package to add Shaolinq and out-of-the-box Sqlite support. + + Designed to perform super fast and be easy to use, Shaolinq's features also include: + + - First class schema-first ORM with WYSIWYG data access and minipulation. + - First class LINQ support (not the basic kind you see in most other OSS projects). + - Single trip updating of objects. + - Support for Sqlite, MySql and Postgres. + - Automatic database creation and schema migration. + - Delete LINQ extension for batch server side deletes. + - Full support for server side date functions (Date.DayOfWeek etc). + - Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. + - Open Source! + + $releasenotes$ + Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) + shaolinq linq provider orm sqlite sql database diff --git a/src/Shaolinq/Shaolinq.csproj b/src/Shaolinq/Shaolinq.csproj index 016cdeb1..6363743d 100644 --- a/src/Shaolinq/Shaolinq.csproj +++ b/src/Shaolinq/Shaolinq.csproj @@ -6,6 +6,33 @@ Shaolinq TRACE;LIBLOG_PUBLIC true + + + Shaolinq + 2.0.0 + Shaolinq ORM and Linq provider + Thong Nguyen + https://raw.github.com/tumtumtum/Shaolinq/master/LICENSE.txt + https://github.com/tumtumtum/Shaolinq + false + + Shaolinq is a thoughtfully designed ORM and Linq provider for .NET + + Designed to perform super fast and be easy to use, Shaolinq's features also include: + + - First class schema-first ORM with WYSIWYG data access and minipulation. + - First class LINQ support (not the basic kind you see in most other OSS projects). + - Single trip updating of objects. + - Support for Sqlite, MySql and Postgres. + - Automatic database creation and schema migration. + - Delete LINQ extension for batch server side deletes. + - Full support for server side date functions (Date.DayOfWeek etc). + - Easily extensible with a simple interface for adding support for other ADO.NET compatible databases. + - Open Source! + + $releasenotes$ + Copyright (c) 2007-2015 Thong Nguyen (tumtumtum@gmail.com) + shaolinq linq provider orm sqlite mysql postgres sql database From 60a69b4a5c8571940acca249dd0ad70846d51a92 Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Wed, 29 Jun 2022 22:23:42 +0200 Subject: [PATCH 10/13] Downgrade Npgsql, due to some breaking changes in it --- docker-compose.yaml | 32 +++++++++++++++++++ .../Shaolinq.Postgres.csproj | 2 +- tests/Shaolinq.Tests/BaseTests.cs | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 docker-compose.yaml diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..c4cf9786 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,32 @@ +version: "3.8" + +networks: + test-stand: + +services: + postgress: + image: stellirin/postgres-windows:latest + environment: + - POSTGRES_PASSWORD=postgres + ports: + - "5432:5432" + networks: + - test-stand + mysql: + image: pomelofoundation/mysql-windows:8-ltsc2019 + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_HOST=% + - MYSQL_ROOT_PASSWORD=root + networks: + - test-stand + mssql: + image: kkbruce/mssql-server-windows-express:windowsservercore-1809 + ports: + - "1433:1433" + environment: + - ACCEPT_EULA=Y + - sa_password=r00t_p@$$w0rd1 + networks: + - test-stand diff --git a/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj b/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj index 54f4798c..72cd84b7 100644 --- a/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj +++ b/src/Shaolinq.Postgres/Shaolinq.Postgres.csproj @@ -36,7 +36,7 @@ - + diff --git a/tests/Shaolinq.Tests/BaseTests.cs b/tests/Shaolinq.Tests/BaseTests.cs index 3aef1985..929a2094 100644 --- a/tests/Shaolinq.Tests/BaseTests.cs +++ b/tests/Shaolinq.Tests/BaseTests.cs @@ -126,7 +126,7 @@ protected DataAccessModelConfiguration CreatePostgresConfiguration(string databa { var retval = PostgresConfiguration.Create(new PostgresSqlDatabaseContextInfo() { - DatabaseName = databaseName, + DatabaseName = databaseName, ServerName = "localhost", UserId = "postgres", Password = "postgres", From 17d54b5575018ec8183501a22b01832270514cfc Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Wed, 29 Jun 2022 22:48:24 +0200 Subject: [PATCH 11/13] SQLigh generates PK AUTOINCREMENT instead of AUTOINCREMENT https://www.sqlite.org/autoinc.html --- src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj | 4 ++-- src/Shaolinq.Sqlite/SqliteSqlDialect.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj b/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj index dade2302..42b9b71b 100644 --- a/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj +++ b/src/Shaolinq.Sqlite/Shaolinq.Sqlite.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -36,7 +36,7 @@ - + diff --git a/src/Shaolinq.Sqlite/SqliteSqlDialect.cs b/src/Shaolinq.Sqlite/SqliteSqlDialect.cs index f9bda276..2a86b80f 100644 --- a/src/Shaolinq.Sqlite/SqliteSqlDialect.cs +++ b/src/Shaolinq.Sqlite/SqliteSqlDialect.cs @@ -30,7 +30,7 @@ public override string GetSyntaxSymbolString(SqlSyntaxSymbol symbol) switch (symbol) { case SqlSyntaxSymbol.AutoIncrement: - return "AUTOINCREMENT"; + return "PRIMARY KEY AUTOINCREMENT"; case SqlSyntaxSymbol.StringQuote: return "'"; case SqlSyntaxSymbol.StringEscape: From ffdb667924158aec3f0b37759e6566ec348933b5 Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Wed, 29 Jun 2022 22:56:21 +0200 Subject: [PATCH 12/13] bump MySql version --- src/Shaolinq.MySql/Shaolinq.MySql.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shaolinq.MySql/Shaolinq.MySql.csproj b/src/Shaolinq.MySql/Shaolinq.MySql.csproj index 62c3dc55..c8c75adf 100644 --- a/src/Shaolinq.MySql/Shaolinq.MySql.csproj +++ b/src/Shaolinq.MySql/Shaolinq.MySql.csproj @@ -36,7 +36,7 @@ Designed to perform super fast and be easy to use, Shaolinq's features also incl - + From 12b4a9f3889ee6c540a809232d50c368236d4b7c Mon Sep 17 00:00:00 2001 From: Anton Sizikov Date: Fri, 1 Jul 2022 13:26:21 +0200 Subject: [PATCH 13/13] Remove old Sqlite lib --- lib/.gitignore | 0 lib/Mono.Data.Sqlite.dll | Bin 171520 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/.gitignore delete mode 100644 lib/Mono.Data.Sqlite.dll diff --git a/lib/.gitignore b/lib/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/Mono.Data.Sqlite.dll b/lib/Mono.Data.Sqlite.dll deleted file mode 100644 index fa7c45b186a7502382ec747db78198c720c6b7ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171520 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 IQ^Vo^0prjqeE