├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── build.yml │ ├── pr.yml │ └── publish.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── .whitesource ├── LICENSE.txt ├── NuGet.config ├── README.md ├── YesSql.sln ├── samples ├── YesSql.Bench │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── YesSql.Bench.csproj ├── YesSql.Samples.FullText │ ├── Indexes │ │ ├── ArticleByWord.cs │ │ └── ArticleIndexProvider.cs │ ├── Models │ │ └── Article.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Tokenizers │ │ ├── ITokenFilter.cs │ │ ├── ITokenizer.cs │ │ ├── StopWordFilter.cs │ │ └── WhiteSpaceTokenizer.cs │ └── YesSql.Samples.FullText.csproj ├── YesSql.Samples.Hi │ ├── Indexes │ │ ├── BlogPostByAuthor.cs │ │ ├── BlogPostByDay.cs │ │ └── BlogPostIndexProvider.cs │ ├── Models │ │ └── BlogPost.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── YesSql.Samples.Hi.csproj ├── YesSql.Samples.Performance │ ├── Benchmarks.cs │ ├── Program.cs │ ├── User.cs │ └── YesSql.Samples.Performance.csproj └── YesSql.Samples.Web │ ├── Controllers │ └── HomeController.cs │ ├── Indexes │ └── BlogPostIndexProvider.cs │ ├── ModelBinding │ ├── FilterEngineModelBinder.cs │ └── QueryFilterEngineModelBinder.cs │ ├── Models │ └── BlogPost.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Services │ └── WebQueryExecutionContext.cs │ ├── ViewModels │ └── BlogPostViewModel.cs │ ├── Views │ ├── Home │ │ └── Index.cshtml │ └── _ViewImports.cshtml │ └── YesSql.Samples.Web.csproj ├── src ├── Directory.Build.props ├── Directory.Packages.props ├── Versions.props ├── YesSql.Abstractions │ ├── Commands │ │ ├── IAddColumnCommand.cs │ │ ├── IAddIndexCommand.cs │ │ ├── IAlterColumnCommand.cs │ │ ├── IAlterTableCommand.cs │ │ ├── IColumnCommand.cs │ │ ├── ICreateColumnCommand.cs │ │ ├── ICreateForeignKeyCommand.cs │ │ ├── ICreateSchemaCommand.cs │ │ ├── ICreateTableCommand.cs │ │ ├── IDropColumnCommand.cs │ │ ├── IDropForeignKeyCommand.cs │ │ ├── IDropIndexCommand.cs │ │ ├── IDropTableCommand.cs │ │ ├── IRenameColumnCommand.cs │ │ ├── ISchemaCommand.cs │ │ ├── ITableCommand.cs │ │ └── SqlStatementCommand.cs │ ├── ConcurrencyException.cs │ ├── Document.cs │ ├── IAccessor.cs │ ├── IAccessorFactory.cs │ ├── ICollection.cs │ ├── ICommandInterpreter.cs │ ├── ICompiledQuery.cs │ ├── IConfiguration.cs │ ├── IConnectionFactory.cs │ ├── IContentSerializer.cs │ ├── IIdGenerator.cs │ ├── IQuery.cs │ ├── ISchemaBuilder.cs │ ├── ISession.cs │ ├── ISqlBuilder.cs │ ├── ISqlDialect.cs │ ├── ISqlFunction.cs │ ├── IStore.cs │ ├── IStringBuilder.cs │ ├── ITableNameConvention.cs │ ├── ITypeService.cs │ ├── IdentityColumnSize.cs │ ├── Indexes │ │ ├── DescribeContext.cs │ │ ├── DescribeFor.cs │ │ ├── IDescriptor.cs │ │ ├── IIndex.cs │ │ ├── IIndexProvider.cs │ │ ├── IndexDescriptor.cs │ │ ├── IndexProvider.cs │ │ ├── MapIndex.cs │ │ └── ReduceIndex.cs │ ├── JoinType.cs │ ├── QueryExtensions.cs │ ├── SchemaBuilderExtensions.cs │ ├── SessionExtensions.cs │ ├── SimplifiedTypeNameAttribute.cs │ ├── SqlBuilderExtensions.cs │ ├── Storage │ │ ├── DocumentIdentity.cs │ │ └── IIdentityEntity.cs │ └── YesSql.Abstractions.csproj ├── YesSql.Core │ ├── Commands │ │ ├── BatchCommand.cs │ │ ├── CreateDocumentCommand.cs │ │ ├── CreateIndexCommand.cs │ │ ├── DeleteDocumentCommand.cs │ │ ├── DeleteMapIndexCommand.cs │ │ ├── DeleteReduceIndexCommand.cs │ │ ├── DocumentCommand.cs │ │ ├── IIndexCommand.cs │ │ ├── IndexCommand.cs │ │ ├── UpdateDocumentCommand.cs │ │ └── UpdateIndexCommand.cs │ ├── Configuration.cs │ ├── ConfigurationExtensions.cs │ ├── Data │ │ ├── AliasBinding.cs │ │ ├── DapperDataHandlers.cs │ │ ├── MapState.cs │ │ ├── NullableThumbprintFactory.cs │ │ ├── PropertyAccessorFactory.cs │ │ ├── WorkDispatcher.cs │ │ └── WorkerQueryKey.cs │ ├── DbConnectionProviderFactory.cs │ ├── GlobalSuppressions.cs │ ├── Indexes │ │ └── IdentityMap.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Provider │ │ ├── BaseDialect.cs │ │ └── ServiceCollectionExtensions.cs │ ├── Serialization │ │ ├── DefaultContentSerializer.cs │ │ ├── DynamicJsonConverter.cs │ │ ├── PropertyInfoAccessor.cs │ │ └── UtcDateTimeJsonConverter.cs │ ├── Services │ │ ├── DbBlockIdGenerator.cs │ │ ├── DefaultIdGenerator.cs │ │ ├── DefaultQuery.cs │ │ ├── DefaultTableNameConvention.cs │ │ ├── EnumerableExtensions.cs │ │ ├── IndexProviderRegisterExtensions.cs │ │ ├── PredicateNodes.cs │ │ └── TypeService.cs │ ├── Session.cs │ ├── SessionState.cs │ ├── Sql │ │ ├── BaseComandInterpreter.cs │ │ ├── MappingFunction.cs │ │ ├── Schema │ │ │ ├── AddColumnCommand.cs │ │ │ ├── AddIndexCommand.cs │ │ │ ├── AlterColumnCommand.cs │ │ │ ├── AlterTableCommand.cs │ │ │ ├── ColumnCommand.cs │ │ │ ├── CreateColumnCommand.cs │ │ │ ├── CreateForeignKeyCommand.cs │ │ │ ├── CreateSchemaCommand.cs │ │ │ ├── CreateTableCommand.cs │ │ │ ├── DropColumnCommand.cs │ │ │ ├── DropForeignKeyCommand.cs │ │ │ ├── DropIndexCommand.cs │ │ │ ├── DropTableCommand.cs │ │ │ ├── RenameColumnCommand .cs │ │ │ ├── SchemaCommand.cs │ │ │ ├── SqlStatementCommand.cs │ │ │ └── TableCommand.cs │ │ ├── SchemaBuilder.cs │ │ ├── SqlBuilder.cs │ │ └── TemplateFunction.cs │ ├── Store.cs │ ├── StoreFactory.cs │ ├── Utils │ │ ├── HashHelper.cs │ │ └── RentedStringBuilder.cs │ └── YesSql.Core.csproj ├── YesSql.Filters.Abstractions │ ├── Builders │ │ ├── BooleanEngineBuilder.cs │ │ ├── DefaultTermEngineBuilder.cs │ │ ├── NamedTermEngineBuilder.cs │ │ ├── OperatorBuilder.cs │ │ ├── TermEngineBuilder.cs │ │ └── UnaryEngineBuilder.cs │ ├── Nodes │ │ ├── FilterNode.cs │ │ ├── OperatorNodes.cs │ │ └── TermNodes.cs │ ├── Services │ │ ├── FilterExecutionContext.cs │ │ ├── FilterResult.cs │ │ ├── IFilterParser.cs │ │ ├── IFilterVisitor.cs │ │ └── TermOption.cs │ └── YesSql.Filters.Abstractions.csproj ├── YesSql.Filters.Query │ ├── IQueryParser.cs │ ├── QueryBooleanEngineBuilder.cs │ ├── QueryEngineBuilder.cs │ ├── QueryEngineBuilderExtensions.cs │ ├── QueryFilterResult.cs │ ├── QueryFilterResultExtensions.cs │ ├── QueryTermEngineBuilderExtensions.cs │ ├── QueryUnaryEngineBuilder.cs │ ├── Services │ │ ├── QueryExecutionContext.cs │ │ ├── QueryFilterVisitor.cs │ │ ├── QueryParseContext.cs │ │ ├── QueryParser.cs │ │ └── QueryTermOption.cs │ └── YesSql.Filters.Query.csproj ├── YesSql.Provider.MySql │ ├── MySqlCommandInterpreter.cs │ ├── MySqlDbProviderOptionsExtensions.cs │ ├── MySqlDialect.cs │ └── YesSql.Provider.MySql.csproj ├── YesSql.Provider.PostgreSql │ ├── PostgreSqlCommandInterpreter.cs │ ├── PostgreSqlDbProviderOptionsExtensions.cs │ ├── PostgreSqlDialect.cs │ └── YesSql.Provider.PostgreSql.csproj ├── YesSql.Provider.SqlServer │ ├── SqlServerComandInterpreter.cs │ ├── SqlServerDbProviderOptionsExtensions.cs │ ├── SqlServerDialect.cs │ └── YesSql.Provider.SqlServer.csproj ├── YesSql.Provider.Sqlite │ ├── GlobalSuppressions.cs │ ├── SqliteCommandInterpreter.cs │ ├── SqliteDbProviderOptionsExtensions.cs │ ├── SqliteDialect.cs │ └── YesSql.Provider.Sqlite.csproj ├── YesSql │ └── YesSql.csproj ├── YesSqlKey.snk └── yessql.pub └── test └── YesSql.Tests ├── Commands └── DeleteDocumentCommand.cs ├── CompiledQueries └── PersonByAgeCompileQuery.cs ├── ConsoleLogger.cs ├── CoreTests.cs ├── DecimalPrecisionAndScaleDataGenerator.cs ├── Filters └── QueryEngineTests.cs ├── GlobalSuppressions.cs ├── HashHelperTests.cs ├── Indexes ├── ArticleByDate.cs ├── ArticleByDay.cs ├── AttachmentByDay.cs ├── Binary.cs ├── CarIndex.cs ├── EmailByAttachment.cs ├── LongestNameByLetter.cs ├── PersonByAge.cs ├── PersonByBothNamesCol.cs ├── PersonByName.cs ├── PersonByNameCol.cs ├── PersonByNullableAge.cs ├── PersonIdentity.cs ├── PersonsByName.cs ├── PropertyIndex.cs ├── PublishedArticles.cs ├── Shapes.cs ├── TypesIndex.cs └── User.cs ├── Models ├── Animal.cs ├── Article.cs ├── Car.cs ├── Drawing.cs ├── Email.cs ├── Person.cs ├── Products.cs ├── Property.cs ├── TestConstants.cs └── Tree.cs ├── MySqlTests.cs ├── NullableThumbprint ├── Discriminators.cs └── NullableThumbprintFactoryTests.cs ├── PostgreSqlLegacyIdentityTests.cs ├── PostgreSqlTests.cs ├── Properties └── AssemblyInfo.cs ├── ProviderTests.cs ├── SqlServer2017Tests.cs ├── SqlServer2019Tests.cs ├── SqlServerTests.cs ├── SqliteLegacyIdentityTests.cs ├── SqliteTests.cs ├── TemporaryFolder.cs ├── TestLogger.cs ├── WorkerQueryKeyTests.cs ├── YesSql.Tests.csproj └── xunit.runner.json /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [sebastienros] 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | groups: 13 | # Grouped version updates configuration 14 | all-dependencies: 15 | patterns: 16 | - "*" 17 | exclude-patterns: 18 | - "*Abstractions" # Don't update abstractions packages 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | bin 3 | Bin 4 | obj 5 | _ReSharper* 6 | *.user 7 | *.patch 8 | *.hg 9 | *.sln.cache 10 | desktop.ini 11 | *.ReSharper 12 | *.orig 13 | *.suo 14 | *.itrace.csdef 15 | *.build.csdef 16 | packages 17 | src/*.testsettings 18 | src/TestResults 19 | src/*.vsmdi 20 | artifacts 21 | *.vsp 22 | project.lock.json 23 | *.mdb 24 | .vs/ 25 | .build/ 26 | .testPublish/ 27 | .idea 28 | yessql.db 29 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:pickProcess}" 9 | }, 10 | { 11 | "name": ".NET Core Launch (Samples.Hi)", 12 | "type": "coreclr", 13 | "request": "launch", 14 | "preLaunchTask": "Dotnet Build Debug", 15 | "program": "${workspaceRoot}/samples/YesSql.Samples.Hi/bin/Debug/netstandardapp1.5/win7-x64/YesSql.Samples.Hi.exe", 16 | "args": [], 17 | "cwd": "${workspaceRoot}/samples/YesSql.Samples.Hi", 18 | "stopAtEntry": false 19 | }, 20 | { 21 | "name": ".NET Core Launch (Samples.Performance)", 22 | "type": "coreclr", 23 | "request": "launch", 24 | "preLaunchTask": "Dotnet Build Debug", 25 | "program": "${workspaceRoot}/samples/YesSql.Samples.Performance/bin/Debug/netstandardapp1.5/win7-x64/YesSql.Samples.Performance.exe", 26 | "args": [], 27 | "cwd": "${workspaceRoot}/samples/YesSql.Samples.Performance", 28 | "stopAtEntry": false 29 | }, 30 | { 31 | "name": ".NET Core Launch (Samples.FullText)", 32 | "type": "coreclr", 33 | "request": "launch", 34 | "preLaunchTask": "Dotnet Build Debug", 35 | "program": "${workspaceRoot}/samples/YesSql.Samples.FullText/bin/Debug/netstandardapp1.5/win7-x64/YesSql.Samples.FullText.exe", 36 | "args": [], 37 | "cwd": "${workspaceRoot}/samples/YesSql.Samples.FullText", 38 | "stopAtEntry": false 39 | }, 40 | { 41 | "name": ".NET Core Launch (Samples.Bench)", 42 | "type": "coreclr", 43 | "request": "launch", 44 | "preLaunchTask": "Dotnet Build Debug", 45 | "program": "${workspaceRoot}/samples/YesSql.Bench/bin/Debug/netstandardapp1.5/win7-x64/YesSql.Bench.exe", 46 | "args": [], 47 | "cwd": "${workspaceRoot}/samples/YesSql.Bench", 48 | "stopAtEntry": false 49 | }, 50 | { 51 | "name": ".NET Core Launch (Samples.Web)", 52 | "type": "coreclr", 53 | "request": "launch", 54 | "preLaunchTask": "Dotnet Build Web Debug", 55 | "program": "${workspaceRoot}/samples/YesSql.Samples.Web/bin/Debug/net5.0/YesSql.Samples.Web.dll", 56 | "args": [], 57 | "cwd": "${workspaceRoot}/samples/YesSql.Samples.Web", 58 | "stopAtEntry": false 59 | }, 60 | ] 61 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "linux": { "command": "sh", "args": ["-c"] }, 4 | "osx": { "command": "sh", "args": ["-c"] }, 5 | "windows": { 6 | "command": "cmd", 7 | "args": [ 8 | "/C" 9 | ] 10 | }, 11 | "tasks": [ 12 | { 13 | "label": "Dotnet Restore", 14 | "type": "shell", 15 | "args": [ 16 | "dotnet restore" 17 | ], 18 | "problemMatcher": [] 19 | }, 20 | { 21 | "label": "Dotnet Force Restore", 22 | "type": "shell", 23 | "args": [ 24 | "dotnet restore --no-cache" 25 | ], 26 | "problemMatcher": [] 27 | }, 28 | { 29 | "label": "Dotnet Rebuild Debug", 30 | "type": "shell", 31 | "args": [ 32 | "dotnet build ${workspaceRoot}/samples/YesSql.Samples.Hi --no-incremental -c Debug" 33 | ], 34 | "problemMatcher": "$msCompile" 35 | }, 36 | { 37 | "label": "Dotnet Build Debug", 38 | "type": "shell", 39 | "args": [ 40 | "dotnet build ${workspaceRoot}/samples/YesSql.Samples.Hi -c Debug" 41 | ], 42 | "problemMatcher": "$msCompile", 43 | "group": { 44 | "_id": "build", 45 | "isDefault": false 46 | } 47 | }, 48 | { 49 | "label": "Dotnet Build Release", 50 | "type": "shell", 51 | "args": [ 52 | "dotnet build ${workspaceRoot}/samples/YesSql.Samples.Hi -c Release" 53 | ], 54 | "problemMatcher": "$msCompile" 55 | }, 56 | { 57 | "label": "Dotnet Run", 58 | "type": "shell", 59 | "args": [ 60 | "cd ${workspaceRoot}/samples/YesSql.Samples.Hi & dotnet run" 61 | ], 62 | "problemMatcher": [] 63 | }, 64 | { 65 | "label": "Dotnet Build Web Debug", 66 | "type": "shell", 67 | "args": [ 68 | "dotnet build ${workspaceRoot}/samples/YesSql.Samples.Web -c Debug" 69 | ], 70 | "problemMatcher": "$msCompile", 71 | "group": { 72 | "_id": "build", 73 | "isDefault": false 74 | } 75 | }, 76 | { 77 | "label": "Gulp Build", 78 | "type": "shell", 79 | "args": [ 80 | "gulp build" 81 | ], 82 | "problemMatcher": "$gulp-tsc" 83 | } 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "scanSettings": { 3 | "baseBranches": [] 4 | }, 5 | "checkRunSettings": { 6 | "vulnerableCheckRunConclusionLevel": "failure", 7 | "displayMode": "diff", 8 | "useMendCheckNames": true 9 | }, 10 | "issueSettings": { 11 | "minSeverityLevel": "LOW", 12 | "issueType": "DEPENDENCY" 13 | } 14 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2012 Sebastien Ros 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/YesSql.Bench/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("YesSql.Bench")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("YesSql.Bench")] 12 | [assembly: AssemblyCopyright("Copyright © 2015")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("1f7e3e43-c859-4090-a0c7-739249a45511")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /samples/YesSql.Bench/YesSql.Bench.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | portable 5 | true 6 | YesSql.Bench 7 | Exe 8 | YesSql.Bench 9 | false 10 | false 11 | false 12 | false 13 | false 14 | false 15 | false 16 | false 17 | false 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Indexes/ArticleByWord.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | 3 | namespace YesSql.Samples.FullText.Indexes 4 | { 5 | public class ArticleByWord : ReduceIndex 6 | { 7 | public string Word { get; set; } 8 | public int Count { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Indexes/ArticleIndexProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using YesSql.Indexes; 3 | using YesSql.Samples.FullText.Models; 4 | using YesSql.Samples.FullText.Tokenizers; 5 | 6 | namespace YesSql.Samples.FullText.Indexes 7 | { 8 | public class ArticleIndexProvider : IndexProvider
9 | { 10 | public override void Describe(DescribeContext
context) 11 | { 12 | var tokenizer = new WhiteSpaceTokenizer(); 13 | var filter = new StopWordFilter(); 14 | 15 | context 16 | .For() 17 | .Map(article => filter 18 | .Filter(tokenizer.Tokenize(article.Content)) 19 | .Select(x => new ArticleByWord { Word = x, Count = 1 }) 20 | ) 21 | .Group(article => article.Word) 22 | .Reduce(group => new ArticleByWord 23 | { 24 | Word = group.Key, 25 | Count = group.Sum(y => y.Count) 26 | }) 27 | .Delete((index, map) => 28 | { 29 | index.Count -= map.Sum(x => x.Count); 30 | 31 | // if Count == 0 then delete the index 32 | return index.Count > 0 ? index : null; 33 | }); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Models/Article.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Samples.FullText.Models 2 | { 3 | public class Article 4 | { 5 | public string Content { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("YesSql.Samples.FullText")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("YesSql.Samples.FullText")] 12 | [assembly: AssemblyCopyright("Copyright © 2015")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("d59b4d5b-43e6-4b9a-94e7-37bbd4686560")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Tokenizers/ITokenFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Samples.FullText.Tokenizers 4 | { 5 | public interface ITokenFilter 6 | { 7 | IEnumerable Filter(IEnumerable tokens); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Tokenizers/ITokenizer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Samples.FullText.Tokenizers 4 | { 5 | public interface ITokenizer 6 | { 7 | IEnumerable Tokenize(string text); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Tokenizers/StopWordFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace YesSql.Samples.FullText.Tokenizers 5 | { 6 | public class StopWordFilter : ITokenFilter 7 | { 8 | public IEnumerable Filter(IEnumerable tokens) 9 | { 10 | return tokens.Where(token => token.Length >= 2); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/Tokenizers/WhiteSpaceTokenizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace YesSql.Samples.FullText.Tokenizers 5 | { 6 | public class WhiteSpaceTokenizer : ITokenizer 7 | { 8 | public IEnumerable Tokenize(string text) 9 | { 10 | var start = 0; 11 | for (var cur = 0; cur < text.Length; cur++) 12 | { 13 | if (Char.IsLetter(text[cur])) continue; 14 | 15 | if (cur - start > 1) 16 | { 17 | yield return text.Substring(start, cur - start); 18 | } 19 | 20 | start = cur + 1; 21 | } 22 | 23 | if (start != text.Length) 24 | { 25 | yield return text.Substring(start); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.FullText/YesSql.Samples.FullText.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | portable 5 | true 6 | YesSql.Samples.FullText 7 | Exe 8 | YesSql.Samples.FullText 9 | false 10 | false 11 | false 12 | false 13 | false 14 | false 15 | false 16 | false 17 | false 18 | 8 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Hi/Indexes/BlogPostByAuthor.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | 3 | namespace YesSql.Samples.Hi.Indexes 4 | { 5 | public class BlogPostByAuthor : MapIndex 6 | { 7 | public string Author { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Hi/Indexes/BlogPostByDay.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | 3 | namespace YesSql.Samples.Hi.Indexes 4 | { 5 | public class BlogPostByDay : ReduceIndex 6 | { 7 | public string Day { get; set; } 8 | public int Count { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Hi/Indexes/BlogPostIndexProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using YesSql.Indexes; 3 | using YesSql.Samples.Hi.Models; 4 | 5 | namespace YesSql.Samples.Hi.Indexes 6 | { 7 | public class BlogPostIndexProvider : IndexProvider 8 | { 9 | public override void Describe(DescribeContext context) 10 | { 11 | // for each BlogPost, create a BlogPostByAuthor index 12 | context.For() 13 | .Map(blogPost => 14 | new BlogPostByAuthor { Author = blogPost.Author } 15 | ); 16 | 17 | // for each BlogPost, aggregate in an exiting BlogPostByDay 18 | context.For() 19 | .Map(blogPost => 20 | new BlogPostByDay 21 | { 22 | Day = blogPost.PublishedUtc.ToString("yyyyMMdd"), 23 | Count = 1 24 | }) 25 | .Group(blogPost => blogPost.Day) 26 | .Reduce(group => 27 | new BlogPostByDay 28 | { 29 | Day = group.Key, 30 | Count = group.Sum(p => p.Count) 31 | }) 32 | .Delete((index, map) => 33 | { 34 | index.Count -= map.Sum(x => x.Count); 35 | 36 | // if Count == 0 then delete the index 37 | return index.Count > 0 ? index : null; 38 | } 39 | ); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /samples/YesSql.Samples.Hi/Models/BlogPost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Samples.Hi.Models 4 | { 5 | public class BlogPost 6 | { 7 | public string Title { get; set; } 8 | public string Author { get; set; } 9 | public string Content { get; set; } 10 | public DateTime PublishedUtc { get; set; } 11 | public string[] Tags { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Hi/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("YesSql.Samples.Hi")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("YesSql.Samples.Hi")] 12 | [assembly: AssemblyCopyright("Copyright © 2015")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("a40bca62-e3a6-4273-b2d2-98f70d19552e")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Hi/YesSql.Samples.Hi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | portable 5 | true 6 | YesSql.Samples.Hi 7 | Exe 8 | YesSql.Samples.Hi 9 | false 10 | false 11 | false 12 | false 13 | false 14 | false 15 | false 16 | false 17 | false 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Performance/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace YesSql.Samples.Performance 4 | { 5 | public class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | var summary = BenchmarkRunner.Run(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Performance/User.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | 3 | namespace YesSql.Samples.Performance 4 | { 5 | public class User 6 | { 7 | //public int Id { get; set; } 8 | public string Email { get; set; } 9 | public string Name { get; set; } 10 | } 11 | 12 | public class UserByName : MapIndex 13 | { 14 | public string Name { get; set; } 15 | } 16 | 17 | public class UserIndexProvider : IndexProvider 18 | { 19 | public override void Describe(DescribeContext context) 20 | { 21 | context.For() 22 | .Map(user => new UserByName { Name = user.Name }); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Performance/YesSql.Samples.Performance.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | YesSql.Samples.Performance 5 | Exe 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/Indexes/BlogPostIndexProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql.Indexes; 3 | using YesSql.Samples.Web.Models; 4 | 5 | namespace YesSql.Samples.Web.Indexes 6 | { 7 | public class BlogPostIndex : MapIndex 8 | { 9 | public string Title { get; set; } 10 | 11 | public string Author { get; set; } 12 | 13 | public string Content { get; set; } 14 | public DateTime PublishedUtc { get; set; } 15 | public bool Published { get; set; } 16 | 17 | } 18 | 19 | public class BlogPostIndexProvider : IndexProvider 20 | { 21 | public override void Describe(DescribeContext context) 22 | { 23 | context 24 | .For() 25 | .Map(blogPost => new BlogPostIndex 26 | { 27 | Title = blogPost.Title, 28 | Author = blogPost.Author, 29 | Content = blogPost.Content, 30 | PublishedUtc = blogPost.PublishedUtc, 31 | Published = blogPost.Published 32 | }); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/ModelBinding/FilterEngineModelBinder.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc.ModelBinding; 5 | 6 | namespace YesSql.Samples.Web.ModelBinding 7 | { 8 | public abstract class FilterEngineModelBinder : IModelBinder 9 | { 10 | public abstract TResult Parse(string text); 11 | 12 | public Task BindModelAsync(ModelBindingContext bindingContext) 13 | { 14 | if (bindingContext == null) 15 | { 16 | throw new ArgumentNullException(nameof(bindingContext)); 17 | } 18 | 19 | var modelName = bindingContext.ModelName; 20 | 21 | // Try to fetch the value of the argument by name q= 22 | var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); 23 | 24 | if (valueProviderResult == ValueProviderResult.None) 25 | { 26 | bindingContext.Result = ModelBindingResult.Success(Parse(string.Empty)); 27 | 28 | return Task.CompletedTask; 29 | } 30 | 31 | bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); 32 | 33 | var value = valueProviderResult.FirstValue; 34 | 35 | // Check if the argument value is null or empty 36 | if (string.IsNullOrEmpty(value)) 37 | { 38 | bindingContext.Result = ModelBindingResult.Success(Parse(string.Empty)); 39 | 40 | return Task.CompletedTask; 41 | } 42 | 43 | var filterResult = Parse(value); 44 | 45 | bindingContext.Result = ModelBindingResult.Success(filterResult); 46 | 47 | return Task.CompletedTask; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/ModelBinding/QueryFilterEngineModelBinder.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Query; 2 | 3 | namespace YesSql.Samples.Web.ModelBinding 4 | { 5 | public class QueryFilterEngineModelBinder : FilterEngineModelBinder> where T : class 6 | { 7 | private readonly IQueryParser _parser; 8 | 9 | public QueryFilterEngineModelBinder(IQueryParser parser) 10 | { 11 | _parser = parser; 12 | } 13 | 14 | public override QueryFilterResult Parse(string text) 15 | => _parser.Parse(text); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/Models/BlogPost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Samples.Web.Models 4 | { 5 | public class BlogPost 6 | { 7 | public long Id { get; set; } 8 | 9 | public string Title { get; set; } 10 | 11 | public string Author { get; set; } 12 | 13 | public string Content { get; set; } 14 | 15 | public DateTime PublishedUtc { get; set; } 16 | public bool Published { get; set; } 17 | 18 | public string[] Tags { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:42529/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "YesSql.Samples.Web": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:42530" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/Services/WebQueryExecutionContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql.Filters.Query.Services; 3 | 4 | namespace YesSql.Samples.Web.Services 5 | { 6 | public class WebQueryExecutionContext : QueryExecutionContext where T : class 7 | { 8 | public WebQueryExecutionContext(IServiceProvider serviceProvider, IQuery query) : base(query) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/ViewModels/BlogPostViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.ModelBinding; 4 | using Microsoft.AspNetCore.Mvc.Rendering; 5 | using YesSql.Samples.Web.Models; 6 | using YesSql.Samples.Web.ModelBinding; 7 | using YesSql.Filters.Query; 8 | 9 | namespace YesSql.Samples.Web.ViewModels 10 | { 11 | public class BlogPostViewModel 12 | { 13 | public IEnumerable BlogPosts { get; set; } 14 | public Filter Search { get; set; } 15 | } 16 | 17 | public class Filter 18 | { 19 | public string Author { get; set; } 20 | public string SearchText { get; set; } 21 | public string OriginalSearchText { get; set; } 22 | public BlogPostStatus SelectedStatus { get; set; } 23 | public BlogPostSort SelectedSort { get; set; } 24 | 25 | [ModelBinder(BinderType = typeof(QueryFilterEngineModelBinder), Name = nameof(SearchText))] 26 | public QueryFilterResult FilterResult { get; set; } 27 | 28 | [BindNever] 29 | public List Statuses { get; set; } = new(); 30 | 31 | [BindNever] 32 | public List Sorts { get; set; } = new(); 33 | } 34 | 35 | public enum BlogPostStatus 36 | { 37 | Default, 38 | Draft, 39 | Published 40 | } 41 | 42 | public enum BlogPostSort 43 | { 44 | Newest, 45 | Oldest, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using YesSql.Samples.Web.Models 2 | @using YesSql.Samples.Web.ViewModels 3 | @using System.Collections.Generic 4 | 5 | @model BlogPostViewModel 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 |
21 |
22 | 23 |
24 | 25 |
26 | 27 |
28 |
29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 | 39 |
40 | 41 | @foreach (var blogPost in Model.BlogPosts) 42 | { 43 |
44 |
45 |

@blogPost.Title

46 | By: @blogPost.Author - Posted: @@ @blogPost.PublishedUtc 47 |

@blogPost.Content

48 |
49 |
50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /samples/YesSql.Samples.Web/YesSql.Samples.Web.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Versions.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.1.66 5 | 6.0.0 6 | 7 | 8 | 9 | 10 | 2.1.35 11 | 12 | 13 | 5.2.2 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IAddColumnCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IAddColumnCommand : ICreateColumnCommand 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IAddIndexCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IAddIndexCommand : ITableCommand 4 | { 5 | string IndexName { get; set; } 6 | string[] ColumnNames { get; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IAlterColumnCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public interface IAlterColumnCommand : IColumnCommand 6 | { 7 | IAlterColumnCommand WithType(Type dbType, int? length); 8 | IAlterColumnCommand WithType(Type dbType, byte precision, byte scale); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IAlterTableCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public interface IAlterTableCommand : ISchemaCommand 6 | { 7 | void AddColumn(string columnName, Type dbType, Action column = null); 8 | void AddColumn(string columnName, Action column = null); 9 | void AlterColumn(string columnName, Action column = null); 10 | void RenameColumn(string columnName, string newName); 11 | void DropColumn(string columnName); 12 | void CreateIndex(string indexName, params string[] columnNames); 13 | void DropIndex(string indexName); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IColumnCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public interface IColumnCommand : ITableCommand 6 | { 7 | string ColumnName { get; } 8 | 9 | byte? Scale { get; } 10 | 11 | byte? Precision { get; } 12 | 13 | Type DbType { get; } 14 | 15 | object Default { get; } 16 | 17 | int? Length { get; } 18 | 19 | IColumnCommand WithDefault(object @default); 20 | 21 | IColumnCommand WithLength(int? length); 22 | 23 | IColumnCommand Unlimited(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/ICreateColumnCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface ICreateColumnCommand : IColumnCommand 4 | { 5 | bool IsUnique { get; } 6 | 7 | bool IsNotNull { get; } 8 | 9 | bool IsPrimaryKey { get; } 10 | 11 | bool IsIdentity { get; } 12 | 13 | ICreateColumnCommand PrimaryKey(); 14 | 15 | ICreateColumnCommand Identity(); 16 | 17 | ICreateColumnCommand WithPrecision(byte? precision); 18 | 19 | ICreateColumnCommand WithScale(byte? scale); 20 | 21 | ICreateColumnCommand NotNull(); 22 | 23 | ICreateColumnCommand Nullable(); 24 | 25 | ICreateColumnCommand Unique(); 26 | 27 | ICreateColumnCommand NotUnique(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/ICreateForeignKeyCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface ICreateForeignKeyCommand : ISchemaCommand 4 | { 5 | string[] DestColumns { get; } 6 | 7 | string DestTable { get; } 8 | 9 | string[] SrcColumns { get; } 10 | 11 | string SrcTable { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/ICreateSchemaCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface ICreateSchemaCommand : ISchemaCommand 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/ICreateTableCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public interface ICreateTableCommand : ISchemaCommand 6 | { 7 | ICreateTableCommand Column(string columnName, Type dbType, Action column = null); 8 | ICreateTableCommand Column(string columnName, Action column = null); 9 | public ICreateTableCommand Column(IdentityColumnSize identityColumnSize, string columnName, Action column = null) => identityColumnSize == IdentityColumnSize.Int32 ? Column(columnName, column) : Column(columnName, column); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IDropColumnCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IDropColumnCommand : IColumnCommand 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IDropForeignKeyCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IDropForeignKeyCommand : ISchemaCommand 4 | { 5 | string SrcTable { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IDropIndexCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IDropIndexCommand : ITableCommand 4 | { 5 | string IndexName { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IDropTableCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IDropTableCommand : ISchemaCommand 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/IRenameColumnCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface IRenameColumnCommand : IColumnCommand 4 | { 5 | string NewColumnName { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/ISchemaCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public interface ISchemaCommand 6 | { 7 | string Name { get; } 8 | List TableCommands { get; } 9 | } 10 | 11 | public enum SchemaCommandType 12 | { 13 | CreateTable, 14 | DropTable, 15 | AlterTable, 16 | SqlStatement, 17 | CreateForeignKey, 18 | DropForeignKey, 19 | CreateSchema, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/ITableCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public interface ITableCommand : ISchemaCommand 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Commands/SqlStatementCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public interface ISqlStatementCommand : ISchemaCommand 6 | { 7 | string Sql { get; } 8 | List Providers { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ConcurrencyException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection.Metadata; 3 | 4 | namespace YesSql 5 | { 6 | public class ConcurrencyException : Exception 7 | { 8 | public Document Document { get; } 9 | 10 | public ConcurrencyException(Document document) : base($"The document with Id '{document.Id}' and type '{document.Type}' could not be updated as it has been changed by another process.") 11 | { 12 | Document = document; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Document.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql 2 | { 3 | /// 4 | /// The class stored in the Document table of a collection. 5 | /// 6 | public class Document 7 | { 8 | /// 9 | /// The unique identifier of the document in the database. 10 | /// 11 | public long Id { get; set; } 12 | 13 | /// 14 | /// The type of the document. 15 | /// 16 | public string Type { get; set; } 17 | 18 | /// 19 | /// Gets or sets the serialized content of the document. 20 | /// 21 | public string Content { get; set; } 22 | 23 | /// 24 | /// Gets or sets the version number of the document. 25 | /// 26 | /// 27 | /// This property is used to track updates, and optionally detect concurrency violations. 28 | /// 29 | public long Version { get; set; } 30 | 31 | /// 32 | /// Clones the current document. 33 | /// 34 | /// A clone of the current document. 35 | public Document Clone() 36 | { 37 | return new Document 38 | { 39 | Id = Id, 40 | Type = Type, 41 | Content = Content, 42 | Version = Version 43 | }; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IAccessor.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql 2 | { 3 | /// 4 | /// An implementation of this interface provides the accessors for the identifier of a 5 | /// document instance. 6 | /// 7 | /// The type of the value to get and set. 8 | public interface IAccessor 9 | { 10 | /// 11 | /// Gets a value of an object. 12 | /// 13 | /// The object to get the value from. 14 | /// The value of the object. 15 | T Get(object obj); 16 | 17 | /// 18 | /// Sets a value of an object. 19 | /// 20 | /// The object to set the value to. 21 | /// The value to set. 22 | void Set(object obj, T value); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IAccessorFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql 4 | { 5 | /// 6 | /// This interface represents a component which can create 7 | /// an instance of in order to 8 | /// get or set a specific value of an object. 9 | /// 10 | public interface IAccessorFactory 11 | { 12 | /// 13 | /// Creates an instance. 14 | /// 15 | IAccessor CreateAccessor(Type tContainer); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ICollection.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql 2 | { 3 | /// 4 | /// A class implementing this interface is associated to a collection. 5 | /// 6 | public interface ICollectionName 7 | { 8 | /// 9 | /// Gets the collection name. 10 | /// 11 | string Collection { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ICommandInterpreter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | using YesSql.Sql.Schema; 4 | 5 | namespace YesSql 6 | { 7 | /// 8 | /// A class implementing this interface can execute database commands. 9 | /// 10 | public interface ICommandInterpreter 11 | { 12 | IEnumerable CreateSql(IEnumerable commands); 13 | IEnumerable Run(ICreateTableCommand command); 14 | IEnumerable Run(IDropTableCommand command); 15 | IEnumerable Run(IAlterTableCommand command); 16 | void Run(StringBuilder builder, IAddColumnCommand command); 17 | void Run(StringBuilder builder, IDropColumnCommand command); 18 | void Run(StringBuilder builder, IAlterColumnCommand command); 19 | void Run(StringBuilder builder, IAddIndexCommand command); 20 | void Run(StringBuilder builder, IDropIndexCommand command); 21 | IEnumerable Run(ISqlStatementCommand command); 22 | IEnumerable Run(ICreateForeignKeyCommand command); 23 | IEnumerable Run(IDropForeignKeyCommand command); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ICompiledQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace YesSql 5 | { 6 | /// 7 | /// And implementation of this interface can be reused 8 | /// to prevent multiple evaluations of the same expression 9 | /// tree. 10 | /// 11 | /// The type of object the query returns. 12 | public interface ICompiledQuery where T : class 13 | { 14 | Expression, IQuery>> Query(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IConnectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Common; 3 | 4 | namespace YesSql 5 | { 6 | /// 7 | /// Represent a component capable of creating instances. 8 | /// 9 | public interface IConnectionFactory 10 | { 11 | /// 12 | /// Creates a instance. 13 | /// 14 | DbConnection CreateConnection(); 15 | 16 | /// 17 | /// Gets the type of the connection is can create. 18 | /// 19 | Type DbConnectionType { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IContentSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql 4 | { 5 | /// 6 | /// This interface represents a components capable of serializing and deserializing 7 | /// an object. 8 | /// 9 | public interface IContentSerializer 10 | { 11 | /// 12 | /// Serializes an object into a . 13 | /// 14 | /// The object to serialize. 15 | /// The serialized object. 16 | string Serialize(object item); 17 | 18 | /// 19 | /// Deserializes an object from a string. 20 | /// 21 | /// The instance representing the object to deserialize. 22 | /// The type of the object to deserialize. 23 | /// The deserialized object. 24 | object Deserialize(string content, Type type); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IIdGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace YesSql 5 | { 6 | /// 7 | /// Represents a component that is able to generate unique identifiers for new documents. 8 | /// Any implementation must be thread-safe. 9 | /// 10 | public interface IIdGenerator 11 | { 12 | /// 13 | /// Invoked when the underlying store is created. 14 | /// 15 | /// The store that this instance is assigned to. 16 | Task InitializeAsync(IStore store); 17 | 18 | /// 19 | /// Initializes a document collection. 20 | /// 21 | Task InitializeCollectionAsync(IConfiguration configuration, string collection); 22 | 23 | /// 24 | /// Generates a unique identifier for the store. 25 | /// 26 | /// The name of the collection to generate the identifier for. 27 | /// A unique identifier 28 | [Obsolete($"Instead, utilize the {nameof(GetNextIdAsync)} method. This current method is slated for removal in upcoming releases.")] 29 | long GetNextId(string collection); 30 | 31 | /// 32 | /// Generates a unique identifier for the store. 33 | /// 34 | /// The name of the collection to generate the identifier for. 35 | /// A unique identifier 36 | Task GetNextIdAsync(string collection); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ISqlBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql 4 | { 5 | /// 6 | /// A class implementing this interface is able to create custom SQL queries. 7 | /// 8 | public interface ISqlBuilder 9 | { 10 | string Clause { get; } 11 | Dictionary Parameters { get; } 12 | string FormatColumn(string table, string column, string schema, bool isAlias = false); 13 | string FormatTable(string table, string schema); 14 | string GetSelector(); 15 | bool HasJoin { get; } 16 | bool HasOrder { get; } 17 | void ClearGroupBy(); 18 | void ClearOrder(); 19 | void OrderBy(string orderBy); 20 | void OrderByDescending(string orderBy); 21 | void OrderByRandom(); 22 | void Select(); 23 | void Selector(string selector); 24 | void Selector(string table, string column, string schema); 25 | void AddSelector(string select); 26 | void InsertSelector(string select); 27 | void Distinct(); 28 | bool HasPaging { get; } 29 | void Skip(string skip); 30 | void Take(string take); 31 | void Table(string table, string alias, string schema); 32 | void From(string from); 33 | void ThenOrderBy(string orderBy); 34 | void ThenOrderByDescending(string orderBy); 35 | void ThenOrderByRandom(); 36 | void Having(string having); 37 | void GroupBy(string groupBy); 38 | void Trail(string trail); 39 | void ClearTrail(); 40 | string ToSqlString(); 41 | void WhereAnd(string clause); 42 | void WhereOr(string clause); 43 | ISqlBuilder Clone(); 44 | IEnumerable GetSelectors(); 45 | IEnumerable GetOrders(); 46 | void Join(JoinType type, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null); 47 | void HavingAnd(string having); 48 | void HavingOr(string having); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ISqlFunction.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql 2 | { 3 | /// 4 | /// A class implementing this interface can be used to represent custom function calls in a dialect. 5 | /// 6 | public interface ISqlFunction 7 | { 8 | 9 | /// 10 | /// Renders the function. 11 | /// 12 | string Render(string[] arguments); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using YesSql.Indexes; 5 | 6 | namespace YesSql 7 | { 8 | public interface IStore : IDisposable 9 | { 10 | /// 11 | /// Creates a new to communicate with the . 12 | /// 13 | ISession CreateSession(bool withTracking = true); 14 | 15 | /// 16 | /// Registers index providers. 17 | /// 18 | /// The index providers to register. 19 | /// The name of the collection. 20 | /// The instance. 21 | IStore RegisterIndexes(IEnumerable indexProviders, string collection = null); 22 | 23 | /// 24 | /// Returns the instance used to create this store. 25 | /// 26 | IConfiguration Configuration { get; } 27 | 28 | /// 29 | /// Initializes the database by creating the required tables and the default collection if necessary. 30 | /// 31 | Task InitializeAsync(); 32 | 33 | /// 34 | /// Initializes a collection in the database by creating the required tables if necessary. 35 | /// 36 | Task InitializeCollectionAsync(string collection); 37 | 38 | /// 39 | /// Create an instance of containing descriptors for all indexes associated to a type and a collection. 40 | /// 41 | IEnumerable Describe(Type target, string collection = null); 42 | 43 | /// 44 | /// Returns the instance used to create this store. 45 | /// 46 | ITypeService TypeNames { get; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IStringBuilder.cs: -------------------------------------------------------------------------------- 1 | // Inspired from https://raw.githubusercontent.com/dotnet/runtime/59c592cc8d2778bcc6173baa2b25b13190e42990/src/libraries/Common/src/System/Text/ValueStringBuilder.cs 2 | 3 | using System; 4 | 5 | namespace YesSql 6 | { 7 | public interface IStringBuilder 8 | { 9 | ref char this[int index] { get; } 10 | 11 | int Capacity { get; } 12 | int Length { get; set; } 13 | 14 | void Append(ReadOnlySpan value); 15 | void Append(string s); 16 | ReadOnlySpan AsSpan(); 17 | ReadOnlySpan AsSpan(int start); 18 | ReadOnlySpan AsSpan(int start, int length); 19 | void Clear(); 20 | void EnsureCapacity(int capacity); 21 | void Insert(int index, char value, int count); 22 | void Insert(int index, string s); 23 | string ToString(); 24 | bool TryCopyTo(Span destination, out int charsWritten); 25 | } 26 | } -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ITableNameConvention.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql 4 | { 5 | /// 6 | /// A class implementing this interface can customize how table names are generated. 7 | /// 8 | public interface ITableNameConvention 9 | { 10 | /// 11 | /// Returns the name of a Document table. 12 | /// 13 | string GetDocumentTable(string collection = null); 14 | 15 | /// 16 | /// Returns the name of an Index table. 17 | /// 18 | string GetIndexTable(Type indexType, string collection = null); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/ITypeService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql 4 | { 5 | /// 6 | /// An implementation of this interface can provide a way to convert a string to a type. 7 | /// 8 | public interface ITypeService 9 | { 10 | /// 11 | /// Gets or sets the string representing a type. 12 | /// 13 | string this[Type t] { get; set; } 14 | 15 | /// 16 | /// Gets the type represented by a string. 17 | /// 18 | Type this[string s] { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/IdentityColumnSize.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql 2 | { 3 | public enum IdentityColumnSize 4 | { 5 | Int32 = 1, 6 | Int64 = 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/DescribeContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace YesSql.Indexes 6 | { 7 | public class DescribeContext : IDescriptor 8 | { 9 | private readonly Dictionary> _describes = new Dictionary>(); 10 | 11 | public IEnumerable Describe(params Type[] types) 12 | { 13 | return _describes 14 | .Where(kp => types == null || types.Length == 0 || types.Contains(kp.Key)) 15 | .SelectMany(x => x.Value) 16 | .Select(kp => new IndexDescriptor 17 | { 18 | Type = kp.IndexType, 19 | Map = kp.GetMap(), 20 | Reduce = kp.GetReduce(), 21 | Delete = kp.GetDelete(), 22 | GroupKey = kp.GroupProperty, 23 | IndexType = kp.IndexType, 24 | Filter = kp.Filter 25 | }); 26 | } 27 | 28 | public IMapFor For() where TIndex : IIndex 29 | { 30 | return For(); 31 | } 32 | 33 | public IMapFor For() where TIndex : IIndex 34 | { 35 | List descriptors; 36 | 37 | if (!_describes.TryGetValue(typeof(T), out descriptors)) 38 | { 39 | descriptors = _describes[typeof(T)] = new List(); 40 | } 41 | 42 | var describeFor = new IndexDescriptor(); 43 | descriptors.Add(describeFor); 44 | 45 | return describeFor; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/IDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace YesSql.Indexes 5 | { 6 | public interface IDescriptor 7 | { 8 | IEnumerable Describe(params Type[] types); 9 | } 10 | } -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/IIndex.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Indexes 4 | { 5 | public interface IIndex 6 | { 7 | long Id { get; set; } 8 | void AddDocument(Document document); 9 | void RemoveDocument(Document document); 10 | IEnumerable GetAddedDocuments(); 11 | IEnumerable GetRemovedDocuments(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/IIndexProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Indexes 4 | { 5 | public interface IIndexProvider 6 | { 7 | void Describe(IDescriptor context); 8 | Type ForType(); 9 | string CollectionName { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/IndexDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | 7 | namespace YesSql.Indexes 8 | { 9 | public class IndexDescriptor 10 | { 11 | public Type Type { get; set; } 12 | public Func>> Map { get; set; } 13 | public Func, IIndex> Reduce { get; set; } 14 | public Func, IIndex> Update { get; set; } 15 | public Func, IIndex> Delete { get; set; } 16 | public PropertyInfo GroupKey { get; set; } 17 | public Type IndexType { get; set; } 18 | public Func Filter { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/IndexProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Indexes 4 | { 5 | public abstract class IndexProvider : IIndexProvider 6 | { 7 | public abstract void Describe(DescribeContext context); 8 | 9 | void IIndexProvider.Describe(IDescriptor context) 10 | { 11 | Describe((DescribeContext)context); 12 | } 13 | 14 | public string CollectionName { get; set; } 15 | 16 | public Type ForType() 17 | { 18 | return typeof(T); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/MapIndex.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Indexes 4 | { 5 | public abstract class MapIndex : IIndex 6 | { 7 | private Document Document { get; set; } 8 | 9 | public long Id { get; set; } 10 | 11 | void IIndex.AddDocument(Document document) 12 | { 13 | Document = document; 14 | } 15 | 16 | void IIndex.RemoveDocument(Document document) 17 | { 18 | Document = null; 19 | } 20 | 21 | IEnumerable IIndex.GetAddedDocuments() 22 | { 23 | yield return Document; 24 | } 25 | 26 | IEnumerable IIndex.GetRemovedDocuments() 27 | { 28 | yield break; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Indexes/ReduceIndex.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Indexes 4 | { 5 | public class ReduceIndex : IIndex 6 | { 7 | public ReduceIndex() 8 | { 9 | Documents = new List(); 10 | } 11 | 12 | public long Id { get; set; } 13 | 14 | List RemovedDocuments = new List(); 15 | 16 | private List Documents { get; set; } 17 | 18 | void IIndex.AddDocument(Document document) 19 | { 20 | Documents.Add(document); 21 | } 22 | 23 | void IIndex.RemoveDocument(Document document) 24 | { 25 | Documents.Remove(document); 26 | RemovedDocuments.Add(document); 27 | } 28 | 29 | IEnumerable IIndex.GetAddedDocuments() 30 | { 31 | return Documents; 32 | } 33 | 34 | IEnumerable IIndex.GetRemovedDocuments() 35 | { 36 | return RemovedDocuments; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/YesSql.Abstractions/JoinType.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql; 2 | 3 | public enum JoinType 4 | { 5 | Inner = 0, 6 | Left = 1, 7 | Right = 2 8 | } 9 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/SimplifiedTypeNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql 4 | { 5 | /// 6 | /// Use this attribute to provide a custom string representation of a type. 7 | /// 8 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate)] 9 | public class SimplifiedTypeNameAttribute : Attribute 10 | { 11 | public string Name { get; set; } 12 | 13 | public SimplifiedTypeNameAttribute(string name) 14 | { 15 | Name = name; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/SqlBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql; 2 | 3 | public static class SqlBuilderExtensions 4 | { 5 | public static void InnerJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null) 6 | => builder.Join(JoinType.Inner, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias); 7 | 8 | public static void LeftJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null) 9 | => builder.Join(JoinType.Left, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias); 10 | 11 | public static void RightJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null) 12 | => builder.Join(JoinType.Right, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias); 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Storage/DocumentIdentity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Storage 4 | { 5 | public class DocumentIdentity : IIdentityEntity 6 | { 7 | public DocumentIdentity(long id, object entity) 8 | { 9 | Id = id; 10 | Entity = entity; 11 | EntityType = entity.GetType(); 12 | } 13 | 14 | public DocumentIdentity(long id, Type type) 15 | { 16 | Id = id; 17 | Entity = null; 18 | EntityType = type; 19 | } 20 | 21 | public long Id { get; set; } 22 | public object Entity { get; set; } 23 | public Type EntityType { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/Storage/IIdentityEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Storage 4 | { 5 | public interface IIdentityEntity 6 | { 7 | long Id { get; set; } 8 | object Entity { get; set; } 9 | Type EntityType { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Abstractions/YesSql.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/YesSql.Core/Commands/CreateDocumentCommand.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data.Common; 6 | using System.Threading.Tasks; 7 | 8 | namespace YesSql.Commands 9 | { 10 | public sealed class CreateDocumentCommand : DocumentCommand 11 | { 12 | private readonly IStore _store; 13 | 14 | public override int ExecutionOrder { get; } = 0; 15 | 16 | public CreateDocumentCommand(Document document, IStore store, string collection) : base(document, collection) 17 | { 18 | _store = store; 19 | } 20 | 21 | public override Task ExecuteAsync(DbConnection connection, DbTransaction transaction, ISqlDialect dialect, ILogger logger) 22 | { 23 | var documentTable = _store.Configuration.TableNameConvention.GetDocumentTable(Collection); 24 | 25 | var insertCmd = $"insert into {dialect.QuoteForTableName(_store.Configuration.TablePrefix + documentTable, _store.Configuration.Schema)} ({dialect.QuoteForColumnName("Id")}, {dialect.QuoteForColumnName("Type")}, {dialect.QuoteForColumnName("Content")}, {dialect.QuoteForColumnName("Version")}) values (@Id, @Type, @Content, @Version);"; 26 | 27 | if (logger.IsEnabled(LogLevel.Trace)) 28 | { 29 | logger.LogTrace(insertCmd); 30 | } 31 | 32 | return connection.ExecuteAsync(insertCmd, Document, transaction); 33 | } 34 | 35 | public override bool AddToBatch(ISqlDialect dialect, List queries, DbCommand batchCommand, List> actions, int index) 36 | { 37 | var documentTable = _store.Configuration.TableNameConvention.GetDocumentTable(Collection); 38 | var insertCmd = $"insert into {dialect.QuoteForTableName(_store.Configuration.TablePrefix + documentTable, _store.Configuration.Schema)} ({dialect.QuoteForColumnName("Id")}, {dialect.QuoteForColumnName("Type")}, {dialect.QuoteForColumnName("Content")}, {dialect.QuoteForColumnName("Version")}) values (@Id_{index}, @Type_{index}, @Content_{index}, @Version_{index});"; 39 | 40 | queries.Add(insertCmd); 41 | 42 | batchCommand 43 | .AddParameter("Id_" + index, Document.Id) 44 | .AddParameter("Type_" + index, Document.Type) 45 | .AddParameter("Content_" + index, Document.Content) 46 | .AddParameter("Version_" + index, Document.Version); 47 | 48 | return true; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/YesSql.Core/Commands/DeleteDocumentCommand.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data.Common; 6 | using System.Threading.Tasks; 7 | 8 | namespace YesSql.Commands 9 | { 10 | public sealed class DeleteDocumentCommand : DocumentCommand 11 | { 12 | private readonly IStore _store; 13 | public override int ExecutionOrder { get; } = 4; 14 | 15 | public DeleteDocumentCommand(Document document, IStore store, string collection) : base(document, collection) 16 | { 17 | _store = store; 18 | } 19 | 20 | public override Task ExecuteAsync(DbConnection connection, DbTransaction transaction, ISqlDialect dialect, ILogger logger) 21 | { 22 | var documentTable = _store.Configuration.TableNameConvention.GetDocumentTable(Collection); 23 | var deleteCmd = $"delete from {dialect.QuoteForTableName(_store.Configuration.TablePrefix + documentTable, _store.Configuration.Schema)} where {dialect.QuoteForColumnName("Id")} = @Id;"; 24 | 25 | if (logger.IsEnabled(LogLevel.Trace)) 26 | { 27 | logger.LogTrace(deleteCmd); 28 | } 29 | 30 | return connection.ExecuteAsync(deleteCmd, Document, transaction); 31 | } 32 | 33 | public override bool AddToBatch(ISqlDialect dialect, List queries, DbCommand command, List> actions, int index) 34 | { 35 | var documentTable = _store.Configuration.TableNameConvention.GetDocumentTable(Collection); 36 | 37 | var deleteCmd = $"delete from {dialect.QuoteForTableName(_store.Configuration.TablePrefix + documentTable, _store.Configuration.Schema)} where {dialect.QuoteForColumnName("Id")} = @Id_{index};"; 38 | queries.Add(deleteCmd); 39 | command.AddParameter($"Id_{index}", Document.Id); 40 | 41 | return true; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/YesSql.Core/Commands/DeleteMapIndexCommand.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data.Common; 6 | using System.Threading.Tasks; 7 | 8 | namespace YesSql.Commands 9 | { 10 | public sealed class DeleteMapIndexCommand : IIndexCommand, ICollectionName 11 | { 12 | private readonly IStore _store; 13 | public long DocumentId { get; } 14 | public Type IndexType { get; } 15 | public string Collection { get; } 16 | public int ExecutionOrder { get; } = 1; 17 | 18 | public DeleteMapIndexCommand(Type indexType, long documentId, IStore store, string collection) 19 | { 20 | IndexType = indexType; 21 | DocumentId = documentId; 22 | Collection = collection; 23 | _store = store; 24 | } 25 | 26 | public Task ExecuteAsync(DbConnection connection, DbTransaction transaction, ISqlDialect dialect, ILogger logger ) 27 | { 28 | var command = $"delete from {dialect.QuoteForTableName(_store.Configuration.TablePrefix + _store.Configuration.TableNameConvention.GetIndexTable(IndexType, Collection), _store.Configuration.Schema)} where {dialect.QuoteForColumnName("DocumentId")} = @Id;"; 29 | 30 | if (logger.IsEnabled(LogLevel.Trace)) 31 | { 32 | logger.LogTrace(command); 33 | } 34 | 35 | return connection.ExecuteAsync(command, new { Id = DocumentId }, transaction); 36 | } 37 | 38 | public bool AddToBatch(ISqlDialect dialect, List queries, DbCommand command, List> actions, int index) 39 | { 40 | var sql = $"delete from {dialect.QuoteForTableName(_store.Configuration.TablePrefix + _store.Configuration.TableNameConvention.GetIndexTable(IndexType, Collection), _store.Configuration.Schema)} where {dialect.QuoteForColumnName("DocumentId")} = @Id_{index};"; 41 | 42 | queries.Add(sql); 43 | 44 | command.AddParameter($"Id_{index}", DocumentId); 45 | 46 | return true; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/YesSql.Core/Commands/DocumentCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data.Common; 5 | using System.Reflection; 6 | using System.Threading.Tasks; 7 | 8 | namespace YesSql.Commands 9 | { 10 | public abstract class DocumentCommand : IIndexCommand, ICollectionName 11 | { 12 | protected static readonly PropertyInfo[] AllProperties = new PropertyInfo[] 13 | { 14 | typeof(Document).GetProperty("Type") 15 | }; 16 | 17 | protected static readonly PropertyInfo[] AllKeys = new PropertyInfo[] 18 | { 19 | typeof(Document).GetProperty("Id") 20 | }; 21 | 22 | public abstract int ExecutionOrder { get; } 23 | 24 | public DocumentCommand(Document document, string collection) 25 | { 26 | Document = document; 27 | Collection = collection; 28 | } 29 | 30 | public Document Document { get; } 31 | 32 | public string Collection { get; } 33 | 34 | public abstract Task ExecuteAsync(DbConnection connection, DbTransaction transaction, ISqlDialect dialect, ILogger logger); 35 | 36 | public abstract bool AddToBatch(ISqlDialect dialect, List queries, DbCommand parameters, List> actions, int index); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/YesSql.Core/Commands/IIndexCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data.Common; 5 | using System.Threading.Tasks; 6 | 7 | namespace YesSql.Commands 8 | { 9 | public interface IIndexCommand 10 | { 11 | Task ExecuteAsync(DbConnection connection, DbTransaction transaction, ISqlDialect dialect, ILogger logger); 12 | bool AddToBatch(ISqlDialect dialect, List queries, DbCommand batchCommand, List> actions, int index); 13 | int ExecutionOrder { get; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/YesSql.Core/Configuration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.Extensions.Logging.Abstractions; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using YesSql.Data; 7 | using YesSql.Serialization; 8 | using YesSql.Services; 9 | 10 | namespace YesSql 11 | { 12 | public class Configuration : IConfiguration 13 | { 14 | public Configuration() 15 | { 16 | IdentifierAccessorFactory = new PropertyAccessorFactory("Id"); 17 | VersionAccessorFactory = new PropertyAccessorFactory("Version"); 18 | ContentSerializer = new DefaultContentSerializer(); 19 | IdGenerator = new DefaultIdGenerator(); 20 | IsolationLevel = IsolationLevel.ReadCommitted; 21 | TablePrefix = ""; 22 | CommandsPageSize = 500; 23 | QueryGatingEnabled = true; 24 | EnableThreadSafetyChecks = false; 25 | Logger = NullLogger.Instance; 26 | ConcurrentTypes = new HashSet(); 27 | TableNameConvention = new DefaultTableNameConvention(); 28 | } 29 | 30 | public IAccessorFactory IdentifierAccessorFactory { get; set; } 31 | public IAccessorFactory VersionAccessorFactory { get; set; } 32 | public IsolationLevel IsolationLevel { get; set; } 33 | public IConnectionFactory ConnectionFactory { get; set; } 34 | public IContentSerializer ContentSerializer { get; set; } 35 | public string TablePrefix { get; set; } 36 | public string Schema { get; set; } 37 | public int CommandsPageSize { get; set; } 38 | public bool QueryGatingEnabled { get; set; } 39 | public bool EnableThreadSafetyChecks { get; set; } 40 | public IIdGenerator IdGenerator { get; set; } 41 | public ILogger Logger { get; set; } 42 | public HashSet ConcurrentTypes { get; } 43 | public ITableNameConvention TableNameConvention { get; set; } 44 | public ICommandInterpreter CommandInterpreter { get; set; } 45 | public ISqlDialect SqlDialect { get; set; } 46 | public IdentityColumnSize IdentityColumnSize { get; set; } = IdentityColumnSize.Int32; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/YesSql.Core/ConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Services; 2 | 3 | namespace YesSql 4 | { 5 | public static class ConfigurationExtensions 6 | { 7 | public static IConfiguration UseDefaultIdGenerator(this IConfiguration configuration) 8 | { 9 | configuration.IdGenerator = new DefaultIdGenerator(); 10 | 11 | return configuration; 12 | } 13 | 14 | public static IConfiguration UseBlockIdGenerator(this IConfiguration configuration, int blockSize = 20) 15 | { 16 | configuration.IdGenerator = new DbBlockIdGenerator(blockSize); 17 | 18 | return configuration; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/YesSql.Core/Data/AliasBinding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Data 4 | { 5 | public class AliasBinding 6 | { 7 | public string Name { get; set; } 8 | 9 | public Type Type { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Core/Data/DapperDataHandlers.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | using System; 3 | using System.Data; 4 | 5 | namespace YesSql.Data 6 | { 7 | abstract class DapperTypeHandler : SqlMapper.TypeHandler 8 | { 9 | public override void SetValue(IDbDataParameter parameter, T value) 10 | => parameter.Value = value; 11 | } 12 | 13 | class DateTimeOffsetHandler : DapperTypeHandler 14 | { 15 | public override DateTimeOffset Parse(object value) 16 | { 17 | switch (value) 18 | { 19 | case null: 20 | return DateTimeOffset.MinValue; 21 | 22 | case string s: 23 | return DateTimeOffset.Parse(s); 24 | 25 | case DateTime dt: 26 | return new DateTimeOffset(dt); 27 | 28 | case DateTimeOffset d: 29 | return d; 30 | 31 | default: 32 | return DateTimeOffset.MinValue; 33 | } 34 | } 35 | } 36 | 37 | class GuidHandler : DapperTypeHandler 38 | { 39 | public override Guid Parse(object value) 40 | { 41 | switch (value) 42 | { 43 | case null: 44 | return Guid.Empty; 45 | 46 | case string s: 47 | return Guid.Parse(s); 48 | 49 | case Guid g: 50 | return g; 51 | 52 | default: 53 | return Guid.Empty; 54 | } 55 | } 56 | } 57 | 58 | class TimeSpanHandler : DapperTypeHandler 59 | { 60 | public override TimeSpan Parse(object value) 61 | { 62 | switch (value) 63 | { 64 | case null: 65 | return TimeSpan.Zero; 66 | 67 | case string s: 68 | return TimeSpan.Parse(s); 69 | 70 | case long l: 71 | return TimeSpan.FromTicks(l); 72 | 73 | case TimeSpan t: 74 | return t; 75 | 76 | default: 77 | return TimeSpan.Zero; 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/YesSql.Core/Data/MapState.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using YesSql.Indexes; 3 | 4 | namespace YesSql.Data 5 | { 6 | public class MapState 7 | { 8 | public MapState(IIndex map, MapStates state) 9 | { 10 | Map = map; 11 | State = state; 12 | 13 | RemovedDocuments = new List(); 14 | AddedDocuments = new List(); 15 | } 16 | 17 | public IIndex Map { get; set; } 18 | public MapStates State { get; set; } 19 | public List RemovedDocuments { get; } 20 | public List AddedDocuments { get; } 21 | } 22 | 23 | public enum MapStates 24 | { 25 | New, 26 | Update, 27 | Delete 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/YesSql.Core/DbConnectionProviderFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Common; 3 | 4 | namespace YesSql 5 | { 6 | /// 7 | /// This class provides methods to create instances of a concrete type. 8 | /// 9 | /// The concrete implementation to instantiate. 10 | public class DbConnectionFactory : IConnectionFactory 11 | where TDbConnection : DbConnection, new() 12 | { 13 | private readonly string _connectionString; 14 | 15 | public Type DbConnectionType => typeof(TDbConnection); 16 | 17 | public DbConnectionFactory(string connectionString) 18 | { 19 | _connectionString = connectionString; 20 | } 21 | 22 | public DbConnection CreateConnection() 23 | { 24 | var connection = new TDbConnection 25 | { 26 | ConnectionString = _connectionString 27 | }; 28 | 29 | return connection; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/YesSql.Core/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | 2 | // This file is used by Code Analysis to maintain SuppressMessage 3 | // attributes that are applied to this project. 4 | // Project-level suppressions either have no target or are given 5 | // a specific target and scoped to a namespace, type, member, etc. 6 | 7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0049:Simplify Names", Justification = "", Scope = "module")] 8 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0037:Use inferred member name", Justification = "", Scope = "module")] 9 | -------------------------------------------------------------------------------- /src/YesSql.Core/Indexes/IdentityMap.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Indexes 4 | { 5 | public class IdentityMap 6 | { 7 | private readonly Dictionary _documentIds = new(); 8 | private readonly Dictionary _entities = new(); 9 | private readonly Dictionary _documents = new(); 10 | 11 | public bool TryGetDocumentId(object item, out long id) 12 | { 13 | return _entities.TryGetValue(item, out id); 14 | } 15 | 16 | public bool TryGetEntityById(long id, out object document) 17 | { 18 | return _documentIds.TryGetValue(id, out document); 19 | } 20 | 21 | public bool HasEntity(object entity) 22 | { 23 | return _entities.ContainsKey(entity); 24 | } 25 | 26 | public void AddEntity(long id, object entity) 27 | { 28 | _entities.Add(entity, id); 29 | _documentIds.Add(id, entity); 30 | } 31 | 32 | public void AddDocument(Document doc) 33 | { 34 | _documents[doc.Id] = doc; 35 | } 36 | 37 | public bool TryGetDocument(long id, out Document doc) 38 | { 39 | return _documents.TryGetValue(id, out doc); 40 | } 41 | 42 | public void Remove(long id, object entity) 43 | { 44 | _entities.Remove(entity); 45 | _documentIds.Remove(id); 46 | _documents.Remove(id); 47 | } 48 | 49 | public IEnumerable GetAll() 50 | { 51 | return _entities.Keys; 52 | } 53 | 54 | public void Clear() 55 | { 56 | _entities.Clear(); 57 | _documentIds.Clear(); 58 | _documents.Clear(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/YesSql.Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("YesSql.Tests,PublicKey=00240000048000009400000006020000002400005253413100040000010001001182125c952dc299d7cecc8ad125b0451fca4baecea957288b7865c6d333bc5110a265d97a502e716bb5b2cc71ea05648c3885f2955065eba8aec2e9225c3e84d5d9bd91929cd20354f479acaa60b76d340844d2161f213fdd324b55c8e79de5c292490c59261f46f97d1872be0cfd5db21a5ea1f02fd245ea35a9296e6e30a7")] -------------------------------------------------------------------------------- /src/YesSql.Core/Provider/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql; 3 | 4 | namespace Microsoft.Extensions.DependencyInjection 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static IServiceCollection AddDbProvider( 9 | this IServiceCollection services, 10 | Action setupAction) 11 | { 12 | ArgumentNullException.ThrowIfNull(services); 13 | 14 | ArgumentNullException.ThrowIfNull(setupAction); 15 | 16 | var config = new Configuration(); 17 | setupAction.Invoke(config); 18 | services.AddSingleton(StoreFactory.CreateAndInitializeAsync(config).GetAwaiter().GetResult()); 19 | 20 | return services; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/YesSql.Core/Serialization/DefaultContentSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace YesSql.Serialization 6 | { 7 | public class DefaultContentSerializer : IContentSerializer 8 | { 9 | private readonly JsonSerializerOptions _options; 10 | 11 | public DefaultContentSerializer() 12 | { 13 | _options = new() 14 | { 15 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull 16 | }; 17 | _options.Converters.Add(UtcDateTimeJsonConverter.Instance); 18 | _options.Converters.Add(DynamicJsonConverter.Instance); 19 | } 20 | 21 | public DefaultContentSerializer(JsonSerializerOptions options) 22 | { 23 | _options = options; 24 | } 25 | 26 | public object Deserialize(string content, Type type) 27 | { 28 | return JsonSerializer.Deserialize(content, type, _options); 29 | } 30 | 31 | public string Serialize(object item) 32 | { 33 | return JsonSerializer.Serialize(item, _options); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/YesSql.Core/Serialization/PropertyInfoAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace YesSql.Serialization 5 | { 6 | public class PropertyInfoAccessor 7 | { 8 | private readonly IInvoker _invoker; 9 | 10 | public PropertyInfoAccessor(PropertyInfo propertyInfo) 11 | { 12 | var delegateType = typeof(Func<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType); 13 | var d = propertyInfo.GetGetMethod().CreateDelegate(delegateType); 14 | 15 | var invokerType = typeof(Invoker<,>).MakeGenericType(propertyInfo.DeclaringType, propertyInfo.PropertyType); 16 | _invoker = Activator.CreateInstance(invokerType, new object[] { d }) as IInvoker; 17 | } 18 | 19 | public object Get(object obj) 20 | { 21 | return _invoker.Invoke(obj); 22 | } 23 | 24 | private interface IInvoker 25 | { 26 | object Invoke(object target); 27 | } 28 | 29 | private sealed class Invoker : IInvoker 30 | { 31 | private readonly Func _d; 32 | 33 | public Invoker(Delegate d) 34 | { 35 | _d = (Func)d; 36 | } 37 | 38 | public object Invoke(object target) 39 | { 40 | return _d((T)target); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/YesSql.Core/Serialization/UtcDateTimeJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace YesSql.Serialization 7 | { 8 | public class UtcDateTimeJsonConverter : JsonConverter 9 | { 10 | public static readonly UtcDateTimeJsonConverter Instance = new(); 11 | 12 | public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 13 | { 14 | Debug.Assert(typeToConvert == typeof(DateTime)); 15 | 16 | if (!reader.TryGetDateTime(out DateTime value)) 17 | { 18 | value = DateTime.UtcNow; 19 | } 20 | 21 | return value; 22 | } 23 | 24 | public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) 25 | { 26 | writer.WriteStringValue(value.ToUniversalTime()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/YesSql.Core/Services/DefaultTableNameConvention.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Services 4 | { 5 | public class DefaultTableNameConvention : ITableNameConvention 6 | { 7 | public const string DocumentTable = "Document"; 8 | 9 | public string GetIndexTable(Type type, string collection = null) 10 | { 11 | if (string.IsNullOrEmpty(collection)) 12 | { 13 | return type.Name; 14 | } 15 | 16 | return collection + "_" + type.Name; 17 | } 18 | 19 | public string GetDocumentTable(string collection = null) 20 | { 21 | if (string.IsNullOrEmpty(collection)) 22 | { 23 | return DocumentTable; 24 | } 25 | 26 | return collection + "_" + DocumentTable; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/YesSql.Core/Services/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using YesSql; 4 | 5 | namespace System 6 | { 7 | public static class EnumerableExtensions 8 | { 9 | public static IEnumerable> PagesOf(this IEnumerable list, int pageSize) 10 | { 11 | if (!list.Any()) 12 | { 13 | yield break; 14 | } 15 | 16 | var page = 0; 17 | var pages = (list.Count() - 1) / pageSize + 1; 18 | 19 | while (page < pages) 20 | { 21 | yield return list.Skip(page * pageSize).Take(pageSize); 22 | page++; 23 | } 24 | } 25 | 26 | public static IEnumerable>> PagesOfByCollection(this IEnumerable list, int pageSize) where T : ICollectionName 27 | { 28 | if (!list.Any()) 29 | { 30 | yield break; 31 | } 32 | 33 | var pagesByCollection = list.GroupBy(x => x.Collection); 34 | 35 | foreach (var group in pagesByCollection) 36 | { 37 | var page = 0; 38 | var pages = (group.Count() - 1) / pageSize + 1; 39 | 40 | while (page < pages) 41 | { 42 | yield return new KeyValuePair>(group.Key, group.Skip(page * pageSize).Take(pageSize)); 43 | page++; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/YesSql.Core/Services/IndexProviderRegisterExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using YesSql.Indexes; 6 | 7 | namespace YesSql 8 | { 9 | public static class IndexProviderRegisterExtensions 10 | { 11 | public static IStore RegisterIndexes(this IStore store, string collection = null) where T : IIndexProvider 12 | { 13 | return store.RegisterIndexes(typeof(T), collection); 14 | } 15 | 16 | public static IStore RegisterIndexes(this IStore store, IIndexProvider indexProvider, string collection = null) 17 | { 18 | if (indexProvider != null) 19 | { 20 | return store.RegisterIndexes([indexProvider], collection); 21 | } 22 | 23 | return store.RegisterIndexes([], collection); 24 | } 25 | 26 | public static IStore RegisterIndexes(this IStore store, Type type, string collection = null) 27 | { 28 | var index = Activator.CreateInstance(type) as IIndexProvider; 29 | 30 | return store.RegisterIndexes(index, collection); 31 | } 32 | 33 | public static IStore RegisterIndexes(this IStore store, IEnumerable types, string collection = null) 34 | { 35 | foreach (var type in types) 36 | { 37 | store.RegisterIndexes(type, collection); 38 | } 39 | 40 | return store.RegisterIndexes([], collection); 41 | } 42 | 43 | public static IStore RegisterIndexes(this IStore store, Assembly assembly, string collection = null) 44 | { 45 | var exportedTypes = assembly.GetExportedTypes(); 46 | var indexes = exportedTypes.Where(x => typeof(IIndexProvider).IsAssignableFrom(x)); 47 | return store.RegisterIndexes(indexes, collection); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/YesSql.Core/Services/TypeService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Reflection; 4 | 5 | namespace YesSql.Services 6 | { 7 | public class TypeService : ITypeService 8 | { 9 | private readonly ConcurrentDictionary typeNames = new(); 10 | 11 | private readonly ConcurrentDictionary nameTypes = new(); 12 | 13 | public string this[Type t] 14 | { 15 | get 16 | { 17 | return typeNames.GetOrAdd(t, type => 18 | { 19 | var typeInfo = t.GetTypeInfo(); 20 | if (IsAnonymousType(typeInfo)) 21 | { 22 | return "dynamic"; 23 | } 24 | 25 | var customName = typeInfo.GetCustomAttribute(); 26 | var calculatedName = string.IsNullOrEmpty(customName?.Name) ? $"{type.FullName}, {typeInfo.Assembly.GetName().Name}" : customName.Name; 27 | nameTypes[calculatedName] = t; 28 | 29 | return calculatedName; 30 | }); 31 | } 32 | 33 | set 34 | { 35 | typeNames[t] = value; 36 | nameTypes[value] = t; 37 | } 38 | } 39 | 40 | public Type this[string s] 41 | { 42 | get 43 | { 44 | if (s == "dynamic") 45 | { 46 | return typeof(object); 47 | } 48 | 49 | return nameTypes[s]; 50 | } 51 | } 52 | 53 | private static bool IsAnonymousType(TypeInfo type) 54 | { 55 | return type.IsGenericType && type.Name.Contains("AnonymousType") 56 | && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) 57 | && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/YesSql.Core/SessionState.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using YesSql.Data; 3 | using YesSql.Indexes; 4 | 5 | namespace YesSql 6 | { 7 | internal sealed class SessionState 8 | { 9 | internal Dictionary> _maps; 10 | public Dictionary> Maps => _maps ??= new Dictionary>(); 11 | 12 | internal IdentityMap _identityMap; 13 | public IdentityMap IdentityMap => _identityMap ??= new IdentityMap(); 14 | 15 | // entities that need to be created in the next flush 16 | internal HashSet _saved; 17 | public HashSet Saved => _saved ??= new HashSet(); 18 | 19 | // entities that already exist and need to be updated in the next flush 20 | internal HashSet _updated; 21 | public HashSet Updated => _updated ??= new HashSet(); 22 | 23 | // entities that are already saved or updated in a previous flush 24 | internal HashSet _tracked; 25 | public HashSet Tracked => _tracked ??= new HashSet(); 26 | 27 | // ids of entities that are checked for concurrency 28 | internal HashSet _concurrent; 29 | public HashSet Concurrent => _concurrent ??= new HashSet(); 30 | 31 | // entities that need to be deleted in the next flush 32 | internal HashSet _deleted; 33 | public HashSet Deleted => _deleted ??= new HashSet(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/MappingFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql 4 | { 5 | public class MappingFunction : ISqlFunction 6 | { 7 | private readonly string _name; 8 | 9 | public MappingFunction(string name) 10 | { 11 | _name = name; 12 | } 13 | 14 | public string Render(string[] arguments) 15 | { 16 | return _name + "(" + string.Join(", ", arguments) + ")"; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/AddColumnCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class AddColumnCommand : CreateColumnCommand, IAddColumnCommand 4 | { 5 | public AddColumnCommand(string tableName, string name) : base(tableName, name) 6 | { 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/AddIndexCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class AddIndexCommand : TableCommand, IAddIndexCommand 4 | { 5 | public string IndexName { get; set; } 6 | 7 | public AddIndexCommand(string tableName, string indexName, params string[] columnNames) 8 | : base(tableName) 9 | { 10 | ColumnNames = columnNames; 11 | IndexName = indexName; 12 | } 13 | 14 | public string[] ColumnNames { get; private set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/AlterColumnCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public class AlterColumnCommand : ColumnCommand, IAlterColumnCommand 6 | { 7 | public AlterColumnCommand(string tableName, string columnName) 8 | : base(tableName, columnName) 9 | { 10 | } 11 | 12 | public new IAlterColumnCommand WithType(Type dbType) 13 | { 14 | base.WithType(dbType); 15 | return this; 16 | } 17 | 18 | public IAlterColumnCommand WithType(Type dbType, int? length) 19 | { 20 | base.WithType(dbType).WithLength(length); 21 | return this; 22 | } 23 | 24 | public IAlterColumnCommand WithType(Type dbType, byte precision, byte scale) 25 | { 26 | base.WithType(dbType); 27 | Precision = precision; 28 | Scale = scale; 29 | return this; 30 | } 31 | 32 | public new IAlterColumnCommand WithLength(int? length) 33 | { 34 | base.WithLength(length); 35 | return this; 36 | } 37 | 38 | public new IAlterColumnCommand Unlimited() 39 | { 40 | return WithLength(16385); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/AlterTableCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public class AlterTableCommand : SchemaCommand, IAlterTableCommand 6 | { 7 | private readonly ISqlDialect _dialect; 8 | private readonly string _tablePrefix; 9 | 10 | public AlterTableCommand(string name, ISqlDialect dialect, string tablePrefix) 11 | : base(name, SchemaCommandType.AlterTable) 12 | { 13 | _dialect = dialect; 14 | _tablePrefix = tablePrefix; 15 | } 16 | 17 | public void AddColumn(string columnName, Type dbType, Action column = null) 18 | { 19 | var command = new AddColumnCommand(Name, columnName); 20 | command.WithType(dbType); 21 | 22 | column?.Invoke(command); 23 | 24 | TableCommands.Add(command); 25 | } 26 | 27 | public void AddColumn(string columnName, Action column = null) 28 | { 29 | AddColumn(columnName, typeof(T), column); 30 | } 31 | 32 | public void DropColumn(string columnName) 33 | { 34 | var command = new DropColumnCommand(Name, columnName); 35 | TableCommands.Add(command); 36 | } 37 | 38 | public void AlterColumn(string columnName, Action column = null) 39 | { 40 | var command = new AlterColumnCommand(Name, columnName); 41 | 42 | column?.Invoke(command); 43 | 44 | TableCommands.Add(command); 45 | } 46 | 47 | public void RenameColumn(string columnName, string newColumnName) 48 | { 49 | var command = new RenameColumnCommand(Name, columnName, newColumnName); 50 | 51 | TableCommands.Add(command); 52 | } 53 | 54 | 55 | public void CreateIndex(string indexName, params string[] columnNames) 56 | { 57 | if (_dialect.PrefixIndex) 58 | { 59 | indexName = _tablePrefix + indexName; 60 | } 61 | 62 | var command = new AddIndexCommand(Name, _dialect.FormatIndexName(indexName), columnNames); 63 | TableCommands.Add(command); 64 | } 65 | 66 | public void DropIndex(string indexName) 67 | { 68 | if (_dialect.PrefixIndex) 69 | { 70 | indexName = _tablePrefix + indexName; 71 | } 72 | 73 | var command = new DropIndexCommand(Name, _dialect.FormatIndexName(indexName)); 74 | TableCommands.Add(command); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/ColumnCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public class ColumnCommand : TableCommand, IColumnCommand 6 | { 7 | public string ColumnName { get; set; } 8 | 9 | public ColumnCommand(string tableName, string name) 10 | : base(tableName) 11 | { 12 | ColumnName = name; 13 | DbType = typeof(object); 14 | Default = null; 15 | Length = null; 16 | Scale = null; 17 | Precision = null; 18 | } 19 | public byte? Scale { get; protected set; } 20 | 21 | public byte? Precision { get; protected set; } 22 | 23 | public Type DbType { get; private set; } 24 | 25 | public object Default { get; private set; } 26 | 27 | public int? Length { get; private set; } 28 | 29 | public IColumnCommand WithType(Type dbType) 30 | { 31 | DbType = dbType; 32 | return this; 33 | } 34 | 35 | public IColumnCommand WithDefault(object @default) 36 | { 37 | Default = @default; 38 | return this; 39 | } 40 | 41 | 42 | public IColumnCommand WithLength(int? length) 43 | { 44 | Length = length; 45 | return this; 46 | } 47 | 48 | public IColumnCommand Unlimited() 49 | { 50 | return WithLength(int.MaxValue); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/CreateColumnCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public class CreateColumnCommand : ColumnCommand, ICreateColumnCommand 6 | { 7 | public CreateColumnCommand(string tableName, string name) : base(tableName, name) 8 | { 9 | IsNotNull = false; 10 | IsUnique = false; 11 | } 12 | 13 | public bool IsUnique { get; protected set; } 14 | 15 | public bool IsNotNull { get; protected set; } 16 | 17 | public bool IsPrimaryKey { get; protected set; } 18 | 19 | public bool IsIdentity { get; protected set; } 20 | 21 | public ICreateColumnCommand PrimaryKey() 22 | { 23 | IsPrimaryKey = true; 24 | IsUnique = false; 25 | return this; 26 | } 27 | 28 | public ICreateColumnCommand Identity() 29 | { 30 | IsIdentity = true; 31 | IsUnique = false; 32 | return this; 33 | } 34 | 35 | public ICreateColumnCommand WithPrecision(byte? precision) 36 | { 37 | Precision = precision; 38 | return this; 39 | } 40 | 41 | public ICreateColumnCommand WithScale(byte? scale) 42 | { 43 | Scale = scale; 44 | return this; 45 | } 46 | 47 | public ICreateColumnCommand NotNull() 48 | { 49 | IsNotNull = true; 50 | return this; 51 | } 52 | 53 | public ICreateColumnCommand Nullable() 54 | { 55 | IsNotNull = false; 56 | return this; 57 | } 58 | 59 | public ICreateColumnCommand Unique() 60 | { 61 | IsUnique = true; 62 | IsPrimaryKey = false; 63 | IsIdentity = false; 64 | return this; 65 | } 66 | 67 | public ICreateColumnCommand NotUnique() 68 | { 69 | IsUnique = false; 70 | return this; 71 | } 72 | 73 | public new ICreateColumnCommand WithLength(int? length) 74 | { 75 | base.WithLength(length); 76 | return this; 77 | } 78 | 79 | public new ICreateColumnCommand Unlimited() 80 | { 81 | return WithLength(10000); 82 | } 83 | 84 | public new ICreateColumnCommand WithType(Type dbType) 85 | { 86 | base.WithType(dbType); 87 | return this; 88 | } 89 | 90 | public new ICreateColumnCommand WithDefault(object @default) 91 | { 92 | base.WithDefault(@default); 93 | return this; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/CreateForeignKeyCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class CreateForeignKeyCommand : SchemaCommand, ICreateForeignKeyCommand 4 | { 5 | public string[] DestColumns { get; private set; } 6 | 7 | public string DestTable { get; private set; } 8 | 9 | public string[] SrcColumns { get; private set; } 10 | 11 | public string SrcTable { get; private set; } 12 | 13 | public CreateForeignKeyCommand(string name, string srcTable, string[] srcColumns, string destTable, string[] destColumns) : base(name, SchemaCommandType.CreateForeignKey) 14 | { 15 | SrcColumns = srcColumns; 16 | DestTable = destTable; 17 | DestColumns = destColumns; 18 | SrcTable = srcTable; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/CreateSchemaCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class CreateSchemaCommand : SchemaCommand, ICreateSchemaCommand 4 | { 5 | public CreateSchemaCommand(string name) 6 | : base(name, SchemaCommandType.CreateSchema) 7 | { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/CreateTableCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public class CreateTableCommand : SchemaCommand, ICreateTableCommand 6 | { 7 | public CreateTableCommand(string name) 8 | : base(name, SchemaCommandType.CreateTable) 9 | { 10 | } 11 | 12 | public ICreateTableCommand Column(string columnName, Type dbType, Action column = null) 13 | { 14 | var command = new CreateColumnCommand(Name, columnName); 15 | command.WithType(dbType); 16 | 17 | column?.Invoke(command); 18 | 19 | TableCommands.Add(command); 20 | return this; 21 | } 22 | 23 | public ICreateTableCommand Column(string columnName, Action column = null) 24 | { 25 | return Column(columnName, typeof(T), column); 26 | } 27 | 28 | public ICreateTableCommand Column(IdentityColumnSize identityColumnSize, string columnName, Action column = null) 29 | => identityColumnSize == IdentityColumnSize.Int32 ? Column(columnName, column) : Column(columnName, column); 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/DropColumnCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class DropColumnCommand : ColumnCommand, IDropColumnCommand 4 | { 5 | public DropColumnCommand(string tableName, string columnName) 6 | : base(tableName, columnName) 7 | { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/DropForeignKeyCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class DropForeignKeyCommand : SchemaCommand, IDropForeignKeyCommand 4 | { 5 | public string SrcTable { get; private set; } 6 | 7 | public DropForeignKeyCommand(string srcTable, string name) 8 | : base(name, SchemaCommandType.DropForeignKey) 9 | { 10 | SrcTable = srcTable; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/DropIndexCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class DropIndexCommand : TableCommand, IDropIndexCommand 4 | { 5 | public string IndexName { get; set; } 6 | 7 | public DropIndexCommand(string tableName, string indexName) 8 | : base(tableName) 9 | { 10 | IndexName = indexName; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/DropTableCommand.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class DropTableCommand : SchemaCommand, IDropTableCommand 4 | { 5 | public DropTableCommand(string name) 6 | : base(name, SchemaCommandType.DropTable) 7 | { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/RenameColumnCommand .cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Sql.Schema 2 | { 3 | public class RenameColumnCommand : ColumnCommand, IRenameColumnCommand 4 | { 5 | public string NewColumnName { get; } 6 | 7 | public RenameColumnCommand(string tableName, string columnName, string newColumnName): base(tableName, columnName) 8 | { 9 | NewColumnName = newColumnName; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/SchemaCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public abstract class SchemaCommand : ISchemaCommand 6 | { 7 | protected SchemaCommand(string name, SchemaCommandType type) 8 | { 9 | TableCommands = new List(); 10 | Type = type; 11 | WithName(name); 12 | } 13 | 14 | public string Name { get; private set; } 15 | public List TableCommands { get; private set; } 16 | 17 | public SchemaCommandType Type { get; private set; } 18 | 19 | public ISchemaCommand WithName(string name) 20 | { 21 | Name = name; 22 | return this; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/SqlStatementCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public class SqlStatementCommand : SchemaCommand, ISqlStatementCommand 6 | { 7 | protected readonly List _providers; 8 | public SqlStatementCommand(string sql) 9 | : base(string.Empty, SchemaCommandType.SqlStatement) 10 | { 11 | Sql = sql; 12 | _providers = new List(); 13 | } 14 | 15 | public string Sql { get; private set; } 16 | public List Providers { get { return _providers; } } 17 | 18 | public ISqlStatementCommand ForProvider(string dataProvider) 19 | { 20 | _providers.Add(dataProvider); 21 | return this; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/Schema/TableCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Sql.Schema 4 | { 5 | public abstract class TableCommand : ITableCommand 6 | { 7 | public string Name { get; private set; } 8 | 9 | public List TableCommands { get; private set; } 10 | 11 | public TableCommand(string tableName) 12 | { 13 | Name = tableName; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/YesSql.Core/Sql/TemplateFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Sql 4 | { 5 | public class TemplateFunction : ISqlFunction 6 | { 7 | private readonly string _template; 8 | 9 | public TemplateFunction(string template) 10 | { 11 | _template = template; 12 | } 13 | 14 | public string Render(string[] arguments) 15 | { 16 | return string.Format(_template, arguments); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/YesSql.Core/StoreFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace YesSql 5 | { 6 | /// 7 | /// Provides methods to configure and create new instances. 8 | /// 9 | public class StoreFactory 10 | { 11 | /// 12 | /// Creates an instance and its new . 13 | /// 14 | /// An action to execute on the of the new instance. 15 | /// The instance will still need to be initialized. 16 | public static IStore Create(Action configuration) 17 | { 18 | var store = new Store(configuration); 19 | return store; 20 | } 21 | 22 | /// 23 | /// Initializes an instance using a specific instance. 24 | /// 25 | /// The instance to use. 26 | /// The instance will still need to be initialized. 27 | public static IStore Create(IConfiguration configuration) 28 | { 29 | var store = new Store(configuration); 30 | return store; 31 | } 32 | 33 | /// 34 | /// Initializes an instance and its new . 35 | /// 36 | /// An action to execute on the of the new instance. 37 | public static async Task CreateAndInitializeAsync(Action configuration) 38 | { 39 | var store = Create(configuration); 40 | await store.InitializeAsync(); 41 | return store; 42 | } 43 | 44 | /// 45 | /// Initializes an instance using a specific instance. 46 | /// 47 | /// The instance to use. 48 | public static async Task CreateAndInitializeAsync(IConfiguration configuration) 49 | { 50 | var store = Create(configuration); 51 | await store.InitializeAsync(); 52 | return store; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/YesSql.Core/YesSql.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Builders/DefaultTermEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Nodes; 2 | using YesSql.Filters.Abstractions.Services; 3 | using Parlot.Fluent; 4 | using static Parlot.Fluent.Parsers; 5 | 6 | namespace YesSql.Filters.Abstractions.Builders 7 | { 8 | public class DefaultTermEngineBuilder : TermEngineBuilder where T : class where TTermOption : TermOption 9 | { 10 | public DefaultTermEngineBuilder(string name) : base(name) 11 | { 12 | } 13 | 14 | public override (Parser Parser, TTermOption TermOption) Build() 15 | { 16 | var op = _operatorParser.Build(); 17 | 18 | var termParser = Terms.Text(Name, caseInsensitive: true) 19 | .AndSkip(Literals.Char(':')) 20 | .And(op.Parser) 21 | .Then(static x => new NamedTermNode(x.Item1, x.Item2)); 22 | 23 | var defaultParser = op.Parser.Then(x => new DefaultTermNode(Name, x)); 24 | 25 | var parser = termParser.Or(defaultParser); 26 | 27 | return (parser, op.TermOption); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Builders/NamedTermEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Nodes; 2 | using YesSql.Filters.Abstractions.Services; 3 | using Parlot.Fluent; 4 | using static Parlot.Fluent.Parsers; 5 | 6 | namespace YesSql.Filters.Abstractions.Builders 7 | { 8 | public class NamedTermEngineBuilder : TermEngineBuilder where TTermOption : TermOption 9 | { 10 | public NamedTermEngineBuilder(string name) : base(name) 11 | { 12 | } 13 | 14 | public override (Parser Parser, TTermOption TermOption) Build() 15 | { 16 | var op = _operatorParser.Build(); 17 | 18 | var parser = Terms.Text(Name, caseInsensitive: true) 19 | .AndSkip(Literals.Char(':')) 20 | .And(op.Parser) 21 | .Then(static x => new NamedTermNode(x.Item1, x.Item2)); 22 | 23 | return (parser, op.TermOption); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Builders/OperatorBuilder.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Nodes; 2 | using YesSql.Filters.Abstractions.Services; 3 | using Parlot.Fluent; 4 | 5 | namespace YesSql.Filters.Abstractions.Builders 6 | { 7 | public abstract class OperatorEngineBuilder where TTermOption : TermOption 8 | { 9 | public abstract (Parser Parser, TTermOption TermOption) Build(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Builders/TermEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Nodes; 2 | using YesSql.Filters.Abstractions.Services; 3 | using Parlot.Fluent; 4 | 5 | namespace YesSql.Filters.Abstractions.Builders 6 | { 7 | public abstract class TermEngineBuilder where TTermOption : TermOption 8 | { 9 | public TermEngineBuilder(string name) 10 | { 11 | Name = name; 12 | } 13 | 14 | public string Name { get; } 15 | public bool Single { get; } 16 | 17 | protected OperatorEngineBuilder _operatorParser; 18 | 19 | public TermEngineBuilder SetOperator(OperatorEngineBuilder operatorParser) 20 | { 21 | _operatorParser = operatorParser; 22 | 23 | return this; 24 | } 25 | 26 | public abstract (Parser Parser, TTermOption TermOption) Build(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Builders/UnaryEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Nodes; 2 | using YesSql.Filters.Abstractions.Services; 3 | using Parlot.Fluent; 4 | using static Parlot.Fluent.Parsers; 5 | 6 | namespace YesSql.Filters.Abstractions.Builders 7 | { 8 | public abstract class UnaryEngineBuilder : OperatorEngineBuilder where TTermOption : TermOption 9 | { 10 | private static readonly Parser _parser = OneOf( 11 | Terms.String(StringLiteralQuotes.Double).Then(static (node) => new UnaryNode(node.ToString(), OperateNodeQuotes.Double)), 12 | Terms.String(StringLiteralQuotes.Single).Then(static (node) => new UnaryNode(node.ToString(), OperateNodeQuotes.Single)), 13 | Terms.NonWhiteSpace().Then(static (node) => new UnaryNode(node.ToString(), OperateNodeQuotes.None)) 14 | ); 15 | 16 | protected TTermOption _termOption; 17 | 18 | public UnaryEngineBuilder(TTermOption termOption) 19 | { 20 | _termOption = termOption; 21 | } 22 | 23 | public UnaryEngineBuilder AllowMultiple() 24 | { 25 | _termOption.Single = false; 26 | 27 | return this; 28 | } 29 | 30 | public UnaryEngineBuilder AlwaysRun() 31 | { 32 | _termOption.AlwaysRun = true; 33 | 34 | return this; 35 | } 36 | 37 | public override (Parser Parser, TTermOption TermOption) Build() 38 | => (_parser, _termOption); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Nodes/FilterNode.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Services; 2 | 3 | namespace YesSql.Filters.Abstractions.Nodes 4 | { 5 | public abstract class FilterNode 6 | { 7 | public abstract string ToNormalizedString(); 8 | 9 | public abstract TResult Accept(IFilterVisitor visitor, TArgument argument); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Services/FilterExecutionContext.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Filters.Abstractions.Services 2 | { 3 | public abstract class FilterExecutionContext 4 | { 5 | public FilterExecutionContext(T item) 6 | { 7 | Item = item; 8 | } 9 | 10 | public T Item { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Services/IFilterParser.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Filters.Abstractions.Services 2 | { 3 | public interface IFilterParser 4 | { 5 | TResult Parse(string text); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Services/IFilterVisitor.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Nodes; 2 | 3 | namespace YesSql.Filters.Abstractions.Services 4 | { 5 | public interface IFilterVisitor 6 | { 7 | TResult Visit(TermNode node, TArgument argument); 8 | TResult Visit(TermOperationNode node, TArgument argument); 9 | TResult Visit(AndTermNode node, TArgument argument); 10 | TResult Visit(UnaryNode node, TArgument argument); 11 | TResult Visit(NotUnaryNode node, TArgument argument); 12 | TResult Visit(OrNode node, TArgument argument); 13 | TResult Visit(AndNode node, TArgument argument); 14 | TResult Visit(GroupNode node, TArgument argument); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/Services/TermOption.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql.Filters.Abstractions.Nodes; 3 | 4 | namespace YesSql.Filters.Abstractions.Services 5 | { 6 | public abstract class TermOption 7 | { 8 | public TermOption(string name) 9 | { 10 | Name = name; 11 | } 12 | 13 | public string Name { get; } 14 | 15 | /// 16 | /// Whether one or many of the specified term is allowed. 17 | /// 18 | public bool Single { get; set; } = true; 19 | 20 | /// 21 | /// Whether this term filter should always run, even when not specified. 22 | /// 23 | public bool AlwaysRun { get; set; } 24 | 25 | public Delegate MapTo { get; set; } 26 | public Delegate MapFrom { get; set; } 27 | public Func MapFromFactory { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Abstractions/YesSql.Filters.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/IQueryParser.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Services; 2 | 3 | namespace YesSql.Filters.Query 4 | { 5 | /// 6 | /// Represents a filter parser for an 7 | /// 8 | public interface IQueryParser : IFilterParser> where T : class 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/QueryBooleanEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using YesSql.Filters.Abstractions.Builders; 4 | using YesSql.Filters.Query.Services; 5 | 6 | namespace YesSql.Filters.Query 7 | { 8 | public class QueryBooleanEngineBuilder : BooleanEngineBuilder> where T : class 9 | { 10 | public QueryBooleanEngineBuilder( 11 | string name, 12 | Func, QueryExecutionContext, ValueTask>> matchQuery, 13 | Func, QueryExecutionContext, ValueTask>> notMatchQuery) 14 | { 15 | _termOption = new QueryTermOption(name, matchQuery, notMatchQuery); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/QueryEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using YesSql.Filters.Abstractions.Builders; 5 | using YesSql.Filters.Query.Services; 6 | 7 | namespace YesSql.Filters.Query 8 | { 9 | /// 10 | /// Builds a for an . 11 | /// 12 | public class QueryEngineBuilder where T : class 13 | { 14 | private readonly Dictionary>> _termBuilders = []; 15 | 16 | public QueryEngineBuilder SetTermParser(TermEngineBuilder> builder) 17 | { 18 | _termBuilders[builder.Name] = builder; 19 | 20 | return this; 21 | } 22 | 23 | public IQueryParser Build() 24 | { 25 | var builders = _termBuilders.Values.Select(x => x.Build()); 26 | 27 | var parsers = builders.Select(x => x.Parser).ToArray(); 28 | var termOptions = builders.Select(x => x.TermOption).ToDictionary(k => k.Name, v => v, StringComparer.OrdinalIgnoreCase); 29 | 30 | return new QueryParser(parsers, termOptions); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/QueryEngineBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql.Filters.Abstractions.Builders; 3 | using YesSql.Filters.Query.Services; 4 | 5 | namespace YesSql.Filters.Query 6 | { 7 | public static class QueryEngineBuilderExtensions 8 | { 9 | /// 10 | /// Adds a term where the name must be specified to an 11 | /// 12 | public static QueryEngineBuilder WithNamedTerm(this QueryEngineBuilder builder, string name, Action>> action) where T : class 13 | { 14 | var parserBuilder = new NamedTermEngineBuilder>(name); 15 | action(parserBuilder); 16 | 17 | builder.SetTermParser(parserBuilder); 18 | return builder; 19 | } 20 | 21 | /// 22 | /// Adds a term where the name is optional to an 23 | /// 24 | public static QueryEngineBuilder WithDefaultTerm(this QueryEngineBuilder builder, string name, Action>> action) where T : class 25 | { 26 | var parserBuilder = new DefaultTermEngineBuilder>(name); 27 | action(parserBuilder); 28 | 29 | builder.SetTermParser(parserBuilder); 30 | return builder; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/QueryFilterResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using YesSql.Filters.Abstractions.Nodes; 5 | using YesSql.Filters.Abstractions.Services; 6 | using YesSql.Filters.Query.Services; 7 | 8 | namespace YesSql.Filters.Query 9 | { 10 | public class QueryFilterResult : FilterResult> where T : class 11 | { 12 | public QueryFilterResult(IReadOnlyDictionary> termOptions) : base(termOptions) 13 | { } 14 | 15 | public QueryFilterResult(IReadOnlyList terms, IReadOnlyDictionary> termOptions) : base(terms, termOptions) 16 | { } 17 | 18 | public void MapFrom(TModel model) 19 | { 20 | foreach (var option in TermOptions) 21 | { 22 | if (option.Value.MapFrom is Action, string, TermOption, TModel> mappingMethod) 23 | { 24 | mappingMethod(this, option.Key, option.Value, model); 25 | } 26 | } 27 | } 28 | 29 | /// 30 | /// Applies term filters to an 31 | /// 32 | public async ValueTask> ExecuteAsync(QueryExecutionContext context) 33 | { 34 | var visitor = new QueryFilterVisitor(); 35 | 36 | foreach (var term in _terms.Values) 37 | { 38 | // TODO optimize value task. 39 | await VisitTerm(TermOptions, context, visitor, term); 40 | } 41 | 42 | // Execute always run terms. These are not added to the terms list. 43 | foreach (var termOption in TermOptions) 44 | { 45 | if (!termOption.Value.AlwaysRun) 46 | { 47 | continue; 48 | } 49 | 50 | if (!_terms.ContainsKey(termOption.Key)) 51 | { 52 | var alwaysRunNode = new NamedTermNode(termOption.Key, new UnaryNode(string.Empty, OperateNodeQuotes.None)); 53 | await VisitTerm(TermOptions, context, visitor, alwaysRunNode); 54 | } 55 | } 56 | 57 | return context.Item; 58 | } 59 | 60 | private async static Task VisitTerm(IReadOnlyDictionary> termOptions, QueryExecutionContext context, QueryFilterVisitor visitor, TermNode term) 61 | { 62 | context.CurrentTermOption = termOptions[term.TermName]; 63 | 64 | var termQuery = visitor.Visit(term, context); 65 | context.Item = await termQuery.Invoke(context.Item); 66 | context.CurrentTermOption = null; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/QueryFilterResultExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using YesSql.Filters.Query.Services; 3 | 4 | namespace YesSql.Filters.Query 5 | { 6 | public static class QueryFilterResultExtensions 7 | { 8 | public static ValueTask> ExecuteAsync(this QueryFilterResult result, IQuery query) where T : class 9 | => result.ExecuteAsync(new QueryExecutionContext(query)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/QueryUnaryEngineBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using YesSql.Filters.Abstractions.Builders; 4 | using YesSql.Filters.Abstractions.Nodes; 5 | using YesSql.Filters.Abstractions.Services; 6 | using YesSql.Filters.Query.Services; 7 | 8 | namespace YesSql.Filters.Query 9 | { 10 | public class QueryUnaryEngineBuilder : UnaryEngineBuilder> where T : class 11 | { 12 | public QueryUnaryEngineBuilder(string name, Func, QueryExecutionContext, ValueTask>> query) : base(new QueryTermOption(name, query)) 13 | { 14 | } 15 | 16 | /// 17 | /// Adds a mapping function which can be applied to a model. 18 | /// The type of model. 19 | /// 20 | public QueryUnaryEngineBuilder MapTo(Action map) 21 | { 22 | _termOption.MapTo = map; 23 | 24 | return this; 25 | } 26 | 27 | /// 28 | /// Adds a mapping function where terms can be mapped from a model. 29 | /// The type of model. 30 | /// Mapping to apply 31 | /// 32 | public QueryUnaryEngineBuilder MapFrom(Func map) 33 | { 34 | static TermNode factory(string name, string value) => new NamedTermNode(name, new UnaryNode(value, OperateNodeQuotes.None)); 35 | 36 | return MapFrom(map, factory); 37 | } 38 | 39 | /// 40 | /// Adds a mapping function where terms can be mapped from a model. 41 | /// The type of model. 42 | /// Mapping to apply 43 | /// Factory to create a when adding a mapping 44 | /// 45 | public QueryUnaryEngineBuilder MapFrom(Func map, Func factory) 46 | { 47 | var mapFrom = (QueryFilterResult terms, string name, TermOption termOption, TModel model) => 48 | { 49 | (var shouldMap, var value) = map(model); 50 | if (shouldMap) 51 | { 52 | var node = termOption.MapFromFactory(name, value); 53 | terms.TryAddOrReplace(node); 54 | } 55 | else 56 | { 57 | terms.TryRemove(name); 58 | } 59 | }; 60 | 61 | _termOption.MapFrom = mapFrom; 62 | _termOption.MapFromFactory = factory; 63 | 64 | return this; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/Services/QueryExecutionContext.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Filters.Abstractions.Services; 2 | 3 | namespace YesSql.Filters.Query.Services 4 | { 5 | public class QueryExecutionContext : FilterExecutionContext> where T : class 6 | { 7 | public QueryExecutionContext(IQuery query) : base(query) 8 | { 9 | } 10 | 11 | public QueryTermOption CurrentTermOption { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/Services/QueryParseContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Parlot; 3 | using Parlot.Fluent; 4 | 5 | namespace YesSql.Filters.Query.Services 6 | { 7 | public class QueryParseContext : ParseContext where T : class 8 | { 9 | public QueryParseContext(IReadOnlyDictionary> termOptions, Scanner scanner, bool useNewLines = false) : base(scanner, useNewLines) 10 | { 11 | TermOptions = termOptions; 12 | } 13 | 14 | public IReadOnlyDictionary> TermOptions { get; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/Services/QueryParser.cs: -------------------------------------------------------------------------------- 1 | using Parlot; 2 | using Parlot.Fluent; 3 | using System.Collections.Generic; 4 | using YesSql.Filters.Abstractions.Nodes; 5 | using static Parlot.Fluent.Parsers; 6 | 7 | namespace YesSql.Filters.Query.Services 8 | { 9 | public class QueryParser : IQueryParser where T : class 10 | { 11 | private readonly Dictionary> _termOptions; 12 | private readonly Parser> _parser; 13 | 14 | public QueryParser(Parser[] termParsers, Dictionary> termOptions) 15 | { 16 | _termOptions = termOptions; 17 | 18 | var terms = OneOf(termParsers); 19 | 20 | _parser = ZeroOrMany(terms) 21 | .Then(static (context, terms) => 22 | { 23 | var ctx = (QueryParseContext)context; 24 | 25 | return new QueryFilterResult(terms, ctx.TermOptions); 26 | }).Compile(); 27 | } 28 | 29 | public QueryFilterResult Parse(string text) 30 | { 31 | if (string.IsNullOrEmpty(text)) 32 | { 33 | return new QueryFilterResult(_termOptions); 34 | } 35 | 36 | var context = new QueryParseContext(_termOptions, new Scanner(text)); 37 | 38 | var result = default(ParseResult>); 39 | if (_parser.Parse(context, ref result)) 40 | { 41 | return result.Value; 42 | } 43 | 44 | return new QueryFilterResult(_termOptions); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/Services/QueryTermOption.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using YesSql.Filters.Abstractions.Services; 4 | 5 | namespace YesSql.Filters.Query.Services 6 | { 7 | public class QueryTermOption : TermOption where T : class 8 | { 9 | public QueryTermOption(string name, Func, QueryExecutionContext, ValueTask>> matchPredicate) : base(name) 10 | { 11 | MatchPredicate = matchPredicate; 12 | } 13 | 14 | public QueryTermOption(string name, Func, QueryExecutionContext, ValueTask>> matchPredicate, Func, QueryExecutionContext, ValueTask>> notMatchPredicate) 15 | : base(name) 16 | { 17 | MatchPredicate = matchPredicate; 18 | NotMatchPredicate = notMatchPredicate; 19 | } 20 | public Func, QueryExecutionContext, ValueTask>> MatchPredicate { get; } 21 | public Func, QueryExecutionContext, ValueTask>> NotMatchPredicate { get; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/YesSql.Filters.Query/YesSql.Filters.Query.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/YesSql.Provider.MySql/MySqlDbProviderOptionsExtensions.cs: -------------------------------------------------------------------------------- 1 | using MySqlConnector; 2 | using System; 3 | using System.Data; 4 | 5 | namespace YesSql.Provider.MySql 6 | { 7 | public static class MySqlDbProviderOptionsExtensions 8 | { 9 | public static IConfiguration UseMySql( 10 | this IConfiguration configuration, 11 | string connectionString, 12 | string schema = null) 13 | { 14 | return UseMySql(configuration, connectionString, IsolationLevel.ReadUncommitted, schema); 15 | } 16 | 17 | public static IConfiguration UseMySql( 18 | this IConfiguration configuration, 19 | string connectionString, 20 | IsolationLevel isolationLevel, 21 | string schema = null) 22 | { 23 | ArgumentNullException.ThrowIfNull(configuration); 24 | 25 | if (string.IsNullOrWhiteSpace(connectionString)) 26 | { 27 | throw new ArgumentException(nameof(connectionString)); 28 | } 29 | 30 | configuration.SqlDialect = new MySqlDialect(); 31 | configuration.Schema = schema; 32 | configuration.CommandInterpreter = new MySqlCommandInterpreter(configuration); 33 | configuration.ConnectionFactory = new DbConnectionFactory(connectionString); 34 | configuration.IsolationLevel = isolationLevel; 35 | 36 | return configuration; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/YesSql.Provider.MySql/YesSql.Provider.MySql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/YesSql.Provider.PostgreSql/PostgreSqlCommandInterpreter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Text; 4 | using YesSql.Sql; 5 | using YesSql.Sql.Schema; 6 | 7 | namespace YesSql.Provider.PostgreSql 8 | { 9 | public class PostgreSqlCommandInterpreter : BaseCommandInterpreter 10 | { 11 | public PostgreSqlCommandInterpreter(IConfiguration configuration) : base(configuration) 12 | { 13 | } 14 | 15 | public override void Run(StringBuilder builder, IAlterColumnCommand command) 16 | { 17 | builder.AppendFormat("alter table {0} alter column {1} ", 18 | _dialect.QuoteForTableName(command.Name, _configuration.Schema), 19 | _dialect.QuoteForColumnName(command.ColumnName)); 20 | 21 | var dbType = _dialect.ToDbType(command.DbType); 22 | 23 | if (dbType != DbType.Object) 24 | { 25 | builder 26 | .Append("type ") 27 | .Append(_dialect.GetTypeName(dbType, command.Length, command.Precision, command.Scale)); 28 | } 29 | else 30 | { 31 | if (command.Length > 0 || command.Precision > 0 || command.Scale > 0) 32 | { 33 | throw new Exception("Error while executing data migration: you need to specify the field's type in order to change its properties"); 34 | } 35 | } 36 | 37 | if (command.Default != null) 38 | { 39 | builder 40 | .Append(" set default ") 41 | .Append(_dialect.GetSqlValue(command.Default)); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/YesSql.Provider.PostgreSql/PostgreSqlDbProviderOptionsExtensions.cs: -------------------------------------------------------------------------------- 1 | using Npgsql; 2 | using System; 3 | using System.Data; 4 | 5 | namespace YesSql.Provider.PostgreSql 6 | { 7 | public static class PostgreSqlDbProviderOptionsExtensions 8 | { 9 | public static IConfiguration UsePostgreSql( 10 | this IConfiguration configuration, 11 | string connectionString, 12 | string schema = null) 13 | { 14 | return UsePostgreSql(configuration, connectionString, IsolationLevel.ReadUncommitted, schema); 15 | } 16 | 17 | public static IConfiguration UsePostgreSql( 18 | this IConfiguration configuration, 19 | string connectionString, 20 | IsolationLevel isolationLevel, 21 | string schema = null) 22 | { 23 | ArgumentNullException.ThrowIfNull(configuration); 24 | 25 | if (string.IsNullOrWhiteSpace(connectionString)) 26 | { 27 | throw new ArgumentException(nameof(connectionString)); 28 | } 29 | 30 | configuration.SqlDialect = new PostgreSqlDialect(); 31 | configuration.Schema = schema; 32 | configuration.CommandInterpreter = new PostgreSqlCommandInterpreter(configuration); 33 | configuration.ConnectionFactory = new DbConnectionFactory(connectionString); 34 | configuration.IsolationLevel = isolationLevel; 35 | 36 | return configuration; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/YesSql.Provider.PostgreSql/YesSql.Provider.PostgreSql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/YesSql.Provider.SqlServer/SqlServerComandInterpreter.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using YesSql.Sql; 3 | using YesSql.Sql.Schema; 4 | 5 | namespace YesSql.Provider.SqlServer 6 | { 7 | public class SqlServerCommandInterpreter : BaseCommandInterpreter 8 | { 9 | public SqlServerCommandInterpreter(IConfiguration configuration) : base(configuration) 10 | { 11 | } 12 | 13 | public override void Run(StringBuilder builder, IRenameColumnCommand command) 14 | { 15 | builder.AppendFormat("EXEC sp_RENAME {0}, {1}, 'COLUMN'", 16 | _dialect.GetSqlValue(_configuration.SqlDialect.QuoteForTableName(command.Name, _configuration.Schema) + "." + _configuration.SqlDialect.QuoteForColumnName(command.ColumnName)), 17 | // Don't [quote] the column name 18 | _dialect.GetSqlValue(command.NewColumnName) 19 | ); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/YesSql.Provider.SqlServer/SqlServerDbProviderOptionsExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.SqlClient; 2 | using System; 3 | using System.Data; 4 | 5 | namespace YesSql.Provider.SqlServer 6 | { 7 | public static class SqlServerDbProviderOptionsExtensions 8 | { 9 | public static IConfiguration UseSqlServer( 10 | this IConfiguration configuration, 11 | string connectionString, 12 | string schema = null) 13 | { 14 | return UseSqlServer(configuration, connectionString, IsolationLevel.ReadUncommitted, schema); 15 | } 16 | 17 | public static IConfiguration UseSqlServer( 18 | this IConfiguration configuration, 19 | string connectionString, 20 | IsolationLevel isolationLevel, 21 | string schema = null) 22 | { 23 | ArgumentNullException.ThrowIfNull(configuration); 24 | 25 | if (string.IsNullOrWhiteSpace(connectionString)) 26 | { 27 | throw new ArgumentException(nameof(connectionString)); 28 | } 29 | 30 | configuration.SqlDialect = new SqlServerDialect(); 31 | configuration.Schema = schema; 32 | configuration.CommandInterpreter = new SqlServerCommandInterpreter(configuration); 33 | configuration.ConnectionFactory = new DbConnectionFactory(connectionString); 34 | configuration.IsolationLevel = isolationLevel; 35 | 36 | return configuration; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/YesSql.Provider.SqlServer/YesSql.Provider.SqlServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/YesSql.Provider.Sqlite/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | 2 | // This file is used by Code Analysis to maintain SuppressMessage 3 | // attributes that are applied to this project. 4 | // Project-level suppressions either have no target or are given 5 | // a specific target and scoped to a namespace, type, member, etc. 6 | 7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0049:Simplify Names", Justification = "", Scope = "module")] -------------------------------------------------------------------------------- /src/YesSql.Provider.Sqlite/SqliteCommandInterpreter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using YesSql.Sql; 3 | using YesSql.Sql.Schema; 4 | 5 | namespace YesSql.Provider.Sqlite 6 | { 7 | public class SqliteCommandInterpreter : BaseCommandInterpreter 8 | { 9 | public SqliteCommandInterpreter(IConfiguration configuration) : base(configuration) 10 | { 11 | } 12 | 13 | public override IEnumerable Run(ICreateForeignKeyCommand command) 14 | { 15 | yield break; 16 | } 17 | 18 | public override IEnumerable Run(IDropForeignKeyCommand command) 19 | { 20 | yield break; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/YesSql.Provider.Sqlite/SqliteDbProviderOptionsExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.Sqlite; 2 | using System; 3 | using System.Data; 4 | 5 | namespace YesSql.Provider.Sqlite 6 | { 7 | public static class SqliteDbProviderOptionsExtensions 8 | { 9 | public static IConfiguration UseSqLite( 10 | this IConfiguration configuration, 11 | string connectionString) 12 | { 13 | return UseSqLite( 14 | configuration, 15 | connectionString, 16 | IsolationLevel.Serializable); 17 | } 18 | 19 | public static IConfiguration UseSqLite( 20 | this IConfiguration configuration, 21 | string connectionString, 22 | IsolationLevel isolationLevel) 23 | { 24 | ArgumentNullException.ThrowIfNull(configuration); 25 | 26 | if (string.IsNullOrWhiteSpace(connectionString)) 27 | { 28 | throw new ArgumentException(nameof(connectionString)); 29 | } 30 | 31 | configuration.SqlDialect = new SqliteDialect(); 32 | configuration.CommandInterpreter = new SqliteCommandInterpreter(configuration); 33 | configuration.ConnectionFactory = new DbConnectionFactory(connectionString); 34 | configuration.IsolationLevel = isolationLevel; 35 | 36 | return configuration; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/YesSql.Provider.Sqlite/YesSql.Provider.Sqlite.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/YesSql/YesSql.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | README.md 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/YesSqlKey.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastienros/yessql/afc74fccd8ce69d77e03b41a3a98f5da0228f3e3/src/YesSqlKey.snk -------------------------------------------------------------------------------- /src/yessql.pub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastienros/yessql/afc74fccd8ce69d77e03b41a3a98f5da0228f3e3/src/yessql.pub -------------------------------------------------------------------------------- /test/YesSql.Tests/Commands/DeleteDocumentCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data.Common; 5 | using System.Threading.Tasks; 6 | using YesSql.Commands; 7 | 8 | namespace YesSql.Tests.Commands 9 | { 10 | public sealed class FailingCommand : DocumentCommand 11 | { 12 | public FailingCommand(Document document) : base(document, null) 13 | { 14 | 15 | } 16 | 17 | public override int ExecutionOrder => 4; 18 | 19 | public override bool AddToBatch(ISqlDialect dialect, List queries, DbCommand command, List> actions, int index) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | 24 | public override Task ExecuteAsync(DbConnection connection, DbTransaction transaction, ISqlDialect dialect, ILogger logger) 25 | { 26 | throw new ApplicationException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/YesSql.Tests/CompiledQueries/PersonByAgeCompileQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using YesSql.Tests.Indexes; 4 | using YesSql.Tests.Models; 5 | 6 | namespace YesSql.Tests.CompiledQueries 7 | { 8 | public class PersonByNameOrAgeQuery : ICompiledQuery 9 | { 10 | public PersonByNameOrAgeQuery(int age, string name) 11 | { 12 | Age = age; 13 | Name = name; 14 | } 15 | 16 | public int Age { get; } 17 | public string Name { get; } 18 | 19 | public Expression, IQuery>> Query() 20 | { 21 | // Because each compiled query has difference caches for each combination of nullable properties, 22 | // it's possible to return different queries when the nullability of a property changes. 23 | // for instance: 24 | // return Name == null 25 | // ? query.With(x => x.Age == Age) 26 | // : query.With(x => x.Age == Age && x.Name == Name); 27 | 28 | return query => query.With(x => x.Age == Age || x.Name == Name); 29 | } 30 | } 31 | 32 | public class PersonOrderedAscQuery : ICompiledQuery 33 | { 34 | public Expression, IQuery>> Query() 35 | { 36 | return query => query.With().OrderBy(x => x.Age); 37 | } 38 | } 39 | 40 | public class PersonOrderedDescQuery : ICompiledQuery 41 | { 42 | public Expression, IQuery>> Query() 43 | { 44 | return query => query.With().OrderByDescending(x => x.Age); 45 | } 46 | } 47 | 48 | public class PersonPagedQuery : ICompiledQuery 49 | { 50 | public Expression, IQuery>> Query() 51 | { 52 | return query => query.With().Take(1); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/YesSql.Tests/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using Xunit.Abstractions; 4 | 5 | namespace YesSql.Tests 6 | { 7 | public class ConsoleLogger : ILogger 8 | { 9 | private readonly ITestOutputHelper _output; 10 | 11 | public ConsoleLogger(ITestOutputHelper output) 12 | { 13 | _output = output; 14 | } 15 | 16 | public IDisposable BeginScope(TState state) 17 | { 18 | return new FakeScope(); 19 | } 20 | 21 | public bool IsEnabled(LogLevel logLevel) 22 | { 23 | return IsLevelEnabled(logLevel); 24 | } 25 | 26 | public bool IsLevelEnabled(LogLevel logLevel) 27 | { 28 | return true; 29 | } 30 | 31 | public void Log(LogLevel logLevel, string log) 32 | { 33 | _output.WriteLine(logLevel.ToString().ToUpper() + ": " + log); 34 | } 35 | 36 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 37 | { 38 | Log(logLevel, formatter(state, exception)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/YesSql.Tests/DecimalPrecisionAndScaleDataGenerator.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace YesSql.Tests 4 | { 5 | 6 | internal sealed class DecimalPrecisionAndScaleDataGenerator : TheoryData 7 | { 8 | public DecimalPrecisionAndScaleDataGenerator() 9 | { 10 | Add(null, null); 11 | Add(1, null); 12 | Add(null, 2); 13 | Add(1, 2); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/YesSql.Tests/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 |  2 | // This file is used by Code Analysis to maintain SuppressMessage 3 | // attributes that are applied to this project. 4 | // Project-level suppressions either have no target or are given 5 | // a specific target and scoped to a namespace, type, member, etc. 6 | 7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0049:Simplify Names", Justification = "", Scope = "member", Target = "~M:YesSql.Tests.CoreTests.ShouldConcatenateMembers~System.Threading.Tasks.Task")] -------------------------------------------------------------------------------- /test/YesSql.Tests/HashHelperTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using YesSql.Utils; 3 | 4 | namespace YesSql.Tests 5 | { 6 | public class HashHelperTests 7 | { 8 | private const string _longKeyName = "MyTablePrefix_FK_LongCollectionName_LongIndexTableName_LongCollectionName_Document_DocumentId"; 9 | 10 | [Fact] 11 | public void ShouldBeDeterministic() 12 | { 13 | var first = HashHelper.HashName("FK_", _longKeyName); 14 | var second = HashHelper.HashName("FK_", _longKeyName); 15 | Assert.Equal(first, second); 16 | } 17 | 18 | [Fact] 19 | public void ShouldBe55Chars() 20 | { 21 | // 52 + FK_ = 55 22 | Assert.Equal(55, HashHelper.HashName("FK_", _longKeyName).Length); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/ArticleByDate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql.Indexes; 3 | using YesSql.Tests.Models; 4 | 5 | namespace YesSql.Tests.Indexes 6 | { 7 | public class ArticleByPublishedDate : MapIndex 8 | { 9 | public string Title { get; set; } 10 | public DateTime PublishedDateTime { get; set; } 11 | } 12 | 13 | public class ArticleBydPublishedDateProvider : IndexProvider
14 | { 15 | public override void Describe(DescribeContext
context) 16 | { 17 | context 18 | .For() 19 | .Map(article => new ArticleByPublishedDate 20 | { 21 | PublishedDateTime = article.PublishedUtc, 22 | Title = article.Title 23 | }); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/ArticleByDay.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using YesSql.Indexes; 3 | using YesSql.Tests.Models; 4 | 5 | namespace YesSql.Tests.Indexes 6 | { 7 | public class ArticlesByDay : ReduceIndex 8 | { 9 | public int Count { get; set; } 10 | public int DayOfYear { get; set; } 11 | } 12 | 13 | public class ArticleIndexProvider : IndexProvider
14 | { 15 | public override void Describe(DescribeContext
context) 16 | { 17 | context 18 | .For() 19 | .Map(article => new ArticlesByDay 20 | { 21 | DayOfYear = article.PublishedUtc.DayOfYear, 22 | Count = 1 23 | }) 24 | .Group(article => article.DayOfYear) 25 | .Reduce(group => new ArticlesByDay 26 | { 27 | DayOfYear = group.Key, 28 | Count = group.Sum(y => y.Count) 29 | }) 30 | .Delete((index, map) => 31 | { 32 | index.Count -= map.Sum(x => x.Count); 33 | 34 | // if Count == 0 then delete the index 35 | return index.Count > 0 ? index : null; 36 | }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/AttachmentByDay.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using YesSql.Indexes; 3 | using YesSql.Tests.Models; 4 | 5 | namespace YesSql.Tests.Indexes 6 | { 7 | public class AttachmentByDay : ReduceIndex 8 | { 9 | public int Date { get; set; } 10 | public int Count { get; set; } 11 | } 12 | 13 | public class AttachmentByDayProvider : IndexProvider 14 | { 15 | public override void Describe(DescribeContext context) 16 | { 17 | context 18 | .For() 19 | /* 20 | * This syntax is equivalent 21 | * 22 | .Map(email => email.Attachements.Select(a => new AttachmentByDay 23 | { 24 | Date = email.Date.DayOfYear, 25 | Count = 1 26 | })) 27 | */ 28 | .Map(email => new AttachmentByDay 29 | { 30 | Date = email.Date.DayOfYear, 31 | Count = email.Attachments.Count 32 | }) 33 | .Group(email => email.Date) 34 | .Reduce(group => new AttachmentByDay 35 | { 36 | Date = group.Key, 37 | Count = group.Sum(y => y.Count) 38 | }) 39 | .Delete((index, map) => 40 | { 41 | index.Count -= map.Sum(x => x.Count); 42 | 43 | // if Count == 0 then delete the index 44 | return index.Count > 0 ? index : null; 45 | }); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/Binary.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class Binary : MapIndex 7 | { 8 | public byte[] Content1 { get; set; } 9 | public byte[] Content2 { get; set; } 10 | public byte[] Content3 { get; set; } 11 | public byte[] Content4 { get; set; } 12 | } 13 | 14 | public class BinaryIndexProvider : IndexProvider 15 | { 16 | public override void Describe(DescribeContext context) 17 | { 18 | context 19 | .For() 20 | .Map(person => new Binary { 21 | Content1 = new byte[255], 22 | Content2 = new byte[8000], 23 | Content3 = new byte[65535], 24 | Content4 = null 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/CarIndex.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class CarIndex : MapIndex 7 | { 8 | public string Name { get; set; } 9 | public Categories Category { get; set; } 10 | } 11 | 12 | public class CarIndexProvider : IndexProvider 13 | { 14 | public override void Describe(DescribeContext context) 15 | { 16 | context 17 | .For() 18 | .Map(c => new CarIndex 19 | { 20 | Name = c.Name, 21 | Category = c.Category, 22 | }); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/EmailByAttachment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using YesSql.Indexes; 4 | using YesSql.Tests.Models; 5 | 6 | namespace YesSql.Tests.Indexes 7 | { 8 | public class EmailByAttachment : MapIndex 9 | { 10 | public DateTime Date { get; set; } 11 | public string AttachmentName { get; set; } 12 | } 13 | 14 | public class EmailByAttachmentProvider : IndexProvider 15 | { 16 | public override void Describe(DescribeContext context) 17 | { 18 | context.For() 19 | .Map(e => e.Attachments.Select(a => new EmailByAttachment() 20 | { 21 | Date = e.Date, 22 | AttachmentName = a.Name 23 | })); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/LongestNameByLetter.cs: -------------------------------------------------------------------------------- 1 | //using System.Linq; 2 | //using YesSql.Indexes; 3 | //using YesSql.Tests.Models; 4 | 5 | //namespace YesSql.Tests.Indexes 6 | //{ 7 | // public class LongestNameByLetter : ReduceIndex 8 | // { 9 | // public char Letter { get; set; } 10 | // public int Length { get; set; } 11 | // public string Name { get; set; } 12 | // } 13 | 14 | // public class LongestNameByLetterIndexProvider : IndexProvider 15 | // { 16 | // public override void Describe(DescribeContext context) 17 | // { 18 | // context 19 | // .For() 20 | // .Map(person => new LongestNameByLetter 21 | // { 22 | // Letter = person.Firstname.FirstOrDefault(), 23 | // Name = person.Firstname, 24 | // Length = person.Firstname.Length 25 | // }) 26 | // .Group(index => index.Letter) 27 | // .Reduce(group => { 28 | // var longest = group.OrderBy(x => x.Name.Length).FirstOrDefault(); 29 | // return new LongestNameByLetter 30 | // { 31 | // Letter = longest.Letter, 32 | // Length = longest.Length, 33 | // Name = longest.Name 34 | // }; 35 | // }) 36 | // ; 37 | // } 38 | // } 39 | //} 40 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonByAge.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PersonByAge : MapIndex 7 | { 8 | public string Name { get; set; } 9 | public int Age { get; set; } 10 | public bool Adult { get; set; } 11 | } 12 | 13 | public class PersonAgeIndexProvider : IndexProvider 14 | { 15 | public override void Describe(DescribeContext context) 16 | { 17 | context 18 | .For() 19 | .Map(person => new PersonByAge 20 | { 21 | Age = person.Age, 22 | Adult = person.Age >= 18, 23 | Name = person.Firstname 24 | }); 25 | } 26 | } 27 | 28 | public class PersonAgeIndexFilterProvider1 : IndexProvider 29 | { 30 | public override void Describe(DescribeContext context) 31 | { 32 | context 33 | .For() 34 | .When(x => x.Age != 0) 35 | .Map(person => new PersonByAge 36 | { 37 | Age = person.Age, 38 | Adult = person.Age >= 18, 39 | Name = person.Firstname 40 | }); 41 | } 42 | } 43 | 44 | public class PersonAgeIndexFilterProvider2 : IndexProvider 45 | { 46 | public override void Describe(DescribeContext context) 47 | { 48 | context 49 | .For() 50 | .Map(person => new PersonByAge 51 | { 52 | Age = person.Age, 53 | Adult = person.Age >= 18, 54 | Name = person.Firstname 55 | }); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonByBothNamesCol.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PersonByBothNamesCol : MapIndex 7 | { 8 | public string Firstname { get; set; } 9 | public string Lastname { get; set; } 10 | } 11 | 12 | public class PersonIndexBothNamesProviderCol : IndexProvider 13 | { 14 | public override void Describe(DescribeContext context) 15 | { 16 | context 17 | .For() 18 | .Map(person => new PersonByBothNamesCol { Firstname = person.Firstname, Lastname = person.Lastname }); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonByName.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using YesSql.Indexes; 3 | using YesSql.Tests.Models; 4 | 5 | namespace YesSql.Tests.Indexes 6 | { 7 | public class PersonByName : MapIndex 8 | { 9 | public string SomeName { get; set; } 10 | public static string Normalize(string name) 11 | { 12 | return name.ToUpperInvariant(); 13 | } 14 | } 15 | 16 | public class PersonIndexProvider : IndexProvider 17 | { 18 | public override void Describe(DescribeContext context) 19 | { 20 | context 21 | .For() 22 | .Map(person => new PersonByName { SomeName = person.Firstname }); 23 | } 24 | } 25 | 26 | public class PersonWithAIndexProvider : IndexProvider 27 | { 28 | public override void Describe(DescribeContext context) 29 | { 30 | context 31 | .For() 32 | .When(p => p.Firstname.StartsWith("A", System.StringComparison.OrdinalIgnoreCase)) 33 | .Map(person => new PersonByName { SomeName = person.Firstname }); 34 | } 35 | } 36 | 37 | public class PersonAsyncIndexProvider : IndexProvider 38 | { 39 | public override void Describe(DescribeContext context) 40 | { 41 | context 42 | .For() 43 | .Map(async person => 44 | { 45 | await Task.Delay(10); 46 | return new PersonByName { SomeName = person.Firstname }; 47 | }); 48 | } 49 | } 50 | 51 | public class ScopedPersonAsyncIndexProvider : IndexProvider 52 | { 53 | private readonly int _seed; 54 | 55 | public ScopedPersonAsyncIndexProvider(int seed) 56 | { 57 | _seed = seed; 58 | } 59 | 60 | public override void Describe(DescribeContext context) 61 | { 62 | context 63 | .For() 64 | .Map(async person => 65 | { 66 | await Task.Delay(10); 67 | return new PersonByName { SomeName = person.Firstname + _seed }; 68 | }); 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonByNameCol.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PersonByNameCol : MapIndex 7 | { 8 | public string Name { get; set; } 9 | } 10 | 11 | public class PersonIndexProviderCol : IndexProvider 12 | { 13 | public override void Describe(DescribeContext context) 14 | { 15 | context 16 | .For() 17 | .Map(person => new PersonByNameCol { Name = person.Firstname }); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonByNullableAge.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PersonByNullableAge : MapIndex 7 | { 8 | public int? Age { get; set; } 9 | } 10 | 11 | public class PersonByNullableAgeIndexProvider : IndexProvider 12 | { 13 | public override void Describe(DescribeContext context) 14 | { 15 | context 16 | .For() 17 | .Map(person => new PersonByNullableAge 18 | { 19 | Age = person.Age > 99 || person.Age < 0 ? default(int?) : person.Age, 20 | }); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonIdentity.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PersonIdentity : MapIndex 7 | { 8 | public PersonIdentity(string identity) 9 | { 10 | Identity = identity; 11 | } 12 | 13 | public string Identity { get; set; } 14 | } 15 | 16 | public class PersonIdentitiesIndexProvider : IndexProvider 17 | { 18 | public override void Describe(DescribeContext context) 19 | { 20 | context 21 | .For() 22 | .Map(p => p.Anonymous ? null: new [] { 23 | new PersonIdentity(p.Firstname), 24 | new PersonIdentity(p.Lastname) 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PersonsByName.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using YesSql.Indexes; 3 | using YesSql.Tests.Models; 4 | 5 | namespace YesSql.Tests.Indexes 6 | { 7 | public class PersonsByNameCol : ReduceIndex 8 | { 9 | public string Name { get; set; } 10 | public int Count { get; set; } 11 | } 12 | 13 | public class PersonsByNameIndexProviderCol : IndexProvider 14 | { 15 | public override void Describe(DescribeContext context) 16 | { 17 | context 18 | .For() 19 | .Map(person => new PersonsByNameCol 20 | { 21 | Name = person.Firstname, 22 | Count = 1 23 | }) 24 | .Group(person => person.Name) 25 | .Reduce(group => new PersonsByNameCol 26 | { 27 | Name = group.Key, 28 | Count = group.Sum(y => y.Count) 29 | }) 30 | .Delete((index, map) => 31 | { 32 | index.Count -= map.Sum(x => x.Count); 33 | 34 | // if Count == 0 then delete the index 35 | return index.Count > 0 ? index : null; 36 | }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PropertyIndex.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PropertyIndex : MapIndex 7 | { 8 | public string Name { get; set; } 9 | public bool ForRent { get; set; } 10 | public bool IsOccupied { get; set; } 11 | public string Location { get; set; } 12 | } 13 | 14 | public class PropertyIndexProvider : IndexProvider 15 | { 16 | public override void Describe(DescribeContext context) 17 | { 18 | context 19 | .For() 20 | .Map(property => new PropertyIndex 21 | { 22 | Name = property.Name, 23 | ForRent = property.ForRent, 24 | IsOccupied = property.IsOccupied, 25 | Location = property.Location 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/PublishedArticles.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class PublishedArticle : MapIndex 7 | { 8 | } 9 | 10 | public class PublishedArticleIndexProvider : IndexProvider
11 | { 12 | public override void Describe(DescribeContext
context) 13 | { 14 | context 15 | .For() 16 | .Map(article => 17 | article.IsPublished ? new PublishedArticle() : null 18 | ); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/Shapes.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | using YesSql.Tests.Models; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class ShapeIndex : MapIndex 7 | { 8 | public string Name { get; set; } 9 | } 10 | 11 | public class ShapeIndexProvider : IndexProvider where TShape : Shape 12 | { 13 | public override void Describe(DescribeContext context) 14 | { 15 | context 16 | .For() 17 | .Map(shape => new ShapeIndex { Name = typeof(TShape).Name }); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/TypesIndex.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using YesSql.Indexes; 3 | 4 | namespace YesSql.Tests.Indexes 5 | { 6 | public class TypesIndex : MapIndex 7 | { 8 | //public char ValueChar { get; set; } 9 | public bool ValueBool { get; set; } 10 | //public sbyte ValueSByte { get; set; } 11 | public short ValueShort { get; set; } 12 | //public ushort ValueUShort { get; set; } 13 | public int ValueInt { get; set; } 14 | //public uint ValueUInt { get; set; } 15 | public long ValueLong { get; set; } 16 | //public ulong ValueULong { get; set; } 17 | public float ValueFloat { get; set; } 18 | public double ValueDouble { get; set; } 19 | public decimal ValueDecimal { get; set; } 20 | public DateTime ValueDateTime { get; set; } 21 | public DateTimeOffset ValueDateTimeOffset { get; set; } 22 | public Guid ValueGuid { get; set; } 23 | public TimeSpan ValueTimeSpan { get; set; } 24 | 25 | //public char? NullableChar { get; set; } 26 | public bool? NullableBool { get; set; } 27 | //public sbyte? NullableSByte { get; set; } 28 | public short? NullableShort { get; set; } 29 | //public ushort? NullableUShort { get; set; } 30 | public int? NullableInt { get; set; } 31 | //public uint? NullableUInt { get; set; } 32 | public long? NullableLong { get; set; } 33 | //public ulong? NullableULong { get; set; } 34 | public float? NullableFloat { get; set; } 35 | public double? NullableDouble { get; set; } 36 | public decimal? NullableDecimal { get; set; } 37 | public DateTime? NullableDateTime { get; set; } 38 | public DateTimeOffset? NullableDateTimeOffset { get; set; } 39 | public Guid? NullableGuid { get; set; } 40 | public TimeSpan? NullableTimeSpan { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Indexes/User.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using YesSql.Indexes; 4 | 5 | namespace YesSql.Tests.Indexes 6 | { 7 | public class User 8 | { 9 | public string UserName { get; set; } 10 | public string NormalizedUserName { get; set; } 11 | public List RoleNames { get; set; } = new List(); 12 | } 13 | 14 | public class UserByRoleNameIndex : ReduceIndex 15 | { 16 | public string RoleName { get; set; } 17 | public int Count { get; set; } 18 | } 19 | 20 | public class UserByRoleNameIndexProvider : IndexProvider 21 | { 22 | 23 | public override void Describe(DescribeContext context) 24 | { 25 | context.For() 26 | .Map(user => user.RoleNames.Select(x => new UserByRoleNameIndex 27 | { 28 | RoleName = x, 29 | Count = 1 30 | })) 31 | .Group(user => user.RoleName) 32 | .Reduce(group => new UserByRoleNameIndex 33 | { 34 | RoleName = group.Key, 35 | Count = group.Sum(x => x.Count) 36 | }) 37 | .Delete((index, map) => 38 | { 39 | index.Count -= map.Sum(x => x.Count); 40 | return index.Count > 0 ? index : null; 41 | }); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Animal.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace YesSql.Tests.Models 4 | { 5 | public class Animal 6 | { 7 | public string Name { get; set; } 8 | 9 | [JsonIgnore] 10 | public string Color { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Article.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace YesSql.Tests.Models 4 | { 5 | public class Article 6 | { 7 | public int Id { get; set; } 8 | public string Title { get; set; } 9 | public DateTime PublishedUtc { get; set; } 10 | public bool IsPublished { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Car.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Tests.Models 2 | { 3 | public class Car 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | public Categories Category { get; set; } 8 | } 9 | 10 | public enum Categories 11 | { 12 | Van, 13 | Truck 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Drawing.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace YesSql.Tests.Models 5 | { 6 | public class Drawing 7 | { 8 | public Drawing() 9 | { 10 | Shapes = new List(); 11 | } 12 | 13 | public IList Shapes { get; set; } 14 | } 15 | 16 | [JsonPolymorphic] 17 | [JsonDerivedType(typeof(Square), nameof(Square))] 18 | [JsonDerivedType(typeof(Circle), nameof(Circle))] 19 | public abstract class Shape 20 | { 21 | public long Id { get; set; } 22 | } 23 | 24 | public class Square : Shape 25 | { 26 | public int Size { get; set; } 27 | } 28 | 29 | public class Circle : Shape 30 | { 31 | public int Radius { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Email.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace YesSql.Tests.Models 5 | { 6 | public class Email 7 | { 8 | public int Id { get; set; } 9 | public List Attachments { get; set; } 10 | public DateTime Date { get; set; } 11 | } 12 | public class Attachment 13 | { 14 | public Attachment(string Name) 15 | { 16 | this.Name = Name; 17 | } 18 | public string Name { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Person.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Tests.Models 2 | { 3 | public class Person 4 | { 5 | public int Id { get; set; } 6 | public string Firstname { get; set; } 7 | public string Lastname { get; set; } 8 | public int Age { get; set; } 9 | public bool Anonymous { get; set; } 10 | public long Version { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Products.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace YesSql.Tests.Models 4 | { 5 | public class Product 6 | { 7 | public int Id { get; set; } 8 | public string Name { get; set; } 9 | public decimal Cost { get; set; } 10 | } 11 | 12 | public class Order 13 | { 14 | public int Id { get; set; } 15 | public string Customer { get; set; } 16 | public IList OrderLines { get; set; } 17 | 18 | public Order() 19 | { 20 | OrderLines = new List(); 21 | } 22 | } 23 | 24 | public class OrderLine 25 | { 26 | public int ProductId { get; set; } 27 | public int Quantity { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Property.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Tests.Models 2 | { 3 | public class Property 4 | { 5 | public string Name { get; set; } 6 | public bool ForRent { get; set; } 7 | public bool IsOccupied { get; set; } 8 | public string Location { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/TestConstants.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Tests.Models 2 | { 3 | public static class TestConstants 4 | { 5 | public static class Strings 6 | { 7 | public const string SomeString = "somestring"; 8 | public const string SomeOtherString = "someotherstring"; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Models/Tree.cs: -------------------------------------------------------------------------------- 1 | namespace YesSql.Tests.Models 2 | { 3 | public class Tree 4 | { 5 | public long Id { get; private set; } 6 | 7 | public string Type { get; set; } 8 | 9 | public int HeightInInches { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/YesSql.Tests/PostgreSqlLegacyIdentityTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Xunit; 3 | using Xunit.Abstractions; 4 | using YesSql.Provider.PostgreSql; 5 | 6 | namespace YesSql.Tests 7 | { 8 | // Docker command 9 | // docker run --name postgresql -e POSTGRES_USER=root -e POSTGRES_PASSWORD=Password12! -e POSTGRES_DB=yessql -d -p 5432:5432 postgres:11 10 | public class PostgreSqlLegacyIdentityTests : PostgreSqlTests 11 | { 12 | public PostgreSqlLegacyIdentityTests(ITestOutputHelper output) : base(output) 13 | { 14 | } 15 | 16 | protected override IConfiguration CreateConfiguration() 17 | { 18 | return new Configuration() 19 | .UsePostgreSql(ConnectionStringBuilder.ConnectionString) 20 | .SetTablePrefix(TablePrefix) 21 | .UseBlockIdGenerator() 22 | .SetIdentityColumnSize(IdentityColumnSize.Int32) 23 | ; 24 | } 25 | 26 | [Fact(Skip = "Skip to make test faster in this configuration")] 27 | public override Task ShouldGateQuery() 28 | { 29 | return base.ShouldGateQuery(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/YesSql.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("YesSql.Tests")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Microsoft")] 11 | [assembly: AssemblyProduct("YesSql.Tests")] 12 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("a3c051ef-4548-4e30-a411-8f49c54b5b72")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | [assembly: AssemblyVersion("1.0.0.0")] 34 | [assembly: AssemblyFileVersion("1.0.0.0")] 35 | -------------------------------------------------------------------------------- /test/YesSql.Tests/ProviderTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.TestHost; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System; 6 | using System.Net; 7 | using System.Threading.Tasks; 8 | using Xunit; 9 | using YesSql.Provider.Sqlite; 10 | 11 | namespace YesSql.Tests 12 | { 13 | public class ProviderTests : IDisposable 14 | { 15 | private readonly TemporaryFolder _tempFolder; 16 | 17 | public ProviderTests() 18 | { 19 | _tempFolder = new TemporaryFolder(); 20 | } 21 | 22 | public void Dispose() 23 | { 24 | // _tempFolder.Dispose(); 25 | } 26 | 27 | [Fact] 28 | public async Task AddedDbProviderStoreShouldPresentInDIContainer() 29 | { 30 | var connectionString = @"Data Source=" + _tempFolder.Folder + "yessql.db;Cache=Shared"; 31 | 32 | // Arrange 33 | var builder = new WebHostBuilder() 34 | .ConfigureServices(services => 35 | { 36 | // Act 37 | services.AddDbProvider(config => config.UseSqLite(connectionString).UseDefaultIdGenerator()); 38 | }) 39 | .Configure(app => 40 | { 41 | app.Run(context => 42 | { 43 | var store = context.RequestServices.GetService(); 44 | 45 | // Assert 46 | Assert.NotNull(store); 47 | return Task.CompletedTask; 48 | }); 49 | }); 50 | 51 | using var server = new TestServer(builder); 52 | var client = server.CreateClient(); 53 | var response = await client.GetAsync("/"); 54 | 55 | Assert.Equal(HttpStatusCode.OK, response.StatusCode); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/YesSql.Tests/SqlServer2017Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.SqlClient; 2 | using System; 3 | using Xunit.Abstractions; 4 | using YesSql.Provider.SqlServer; 5 | 6 | namespace YesSql.Tests 7 | { 8 | public class SqlServer2017Tests : SqlServerTests 9 | { 10 | // Docker command 11 | // docker run --name sqlserver2017 -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Password12!" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest 12 | 13 | public override SqlConnectionStringBuilder ConnectionStringBuilder => new(Environment.GetEnvironmentVariable("SQLSERVER_2017_CONNECTION_STRING") ?? @"Server=127.0.0.1;Database=tempdb;User Id=sa;Password=Password12!;Encrypt=False"); 14 | 15 | public SqlServer2017Tests(ITestOutputHelper output) : base(output) 16 | { 17 | } 18 | 19 | protected override IConfiguration CreateConfiguration() 20 | { 21 | return new Configuration() 22 | .UseSqlServer(ConnectionStringBuilder.ConnectionString, "BobaFett") 23 | .SetTablePrefix(TablePrefix) 24 | .UseBlockIdGenerator() 25 | .SetIdentityColumnSize(IdentityColumnSize.Int64) 26 | ; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/YesSql.Tests/SqlServer2019Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.SqlClient; 2 | using System; 3 | using Xunit.Abstractions; 4 | using YesSql.Provider.SqlServer; 5 | 6 | namespace YesSql.Tests 7 | { 8 | public class SqlServer2019Tests : SqlServerTests 9 | { 10 | // Docker command 11 | // docker run --name sqlserver2019 -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Password12!" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest 12 | public override SqlConnectionStringBuilder ConnectionStringBuilder => new(Environment.GetEnvironmentVariable("SQLSERVER_2019_CONNECTION_STRING") ?? @"Server=127.0.0.1;Database=tempdb;User Id=sa;Password=Password12!;Encrypt=False"); 13 | 14 | public SqlServer2019Tests(ITestOutputHelper output) : base(output) 15 | { 16 | } 17 | 18 | protected override IConfiguration CreateConfiguration() 19 | { 20 | return new Configuration() 21 | .UseSqlServer(ConnectionStringBuilder.ConnectionString, "BobaFett") 22 | .SetTablePrefix(TablePrefix) 23 | .UseBlockIdGenerator() 24 | .SetIdentityColumnSize(IdentityColumnSize.Int64) 25 | ; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/YesSql.Tests/SqliteLegacyIdentityTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Xunit; 3 | using Xunit.Abstractions; 4 | using YesSql.Provider.Sqlite; 5 | 6 | namespace YesSql.Tests 7 | { 8 | /// 9 | /// Run all tests with a Sqlite document storage 10 | /// 11 | public class SqliteLegacyIdentityTests : SqliteTests 12 | { 13 | private TemporaryFolder _tempFolder; 14 | 15 | public SqliteLegacyIdentityTests(ITestOutputHelper output) : base(output) 16 | { 17 | } 18 | 19 | protected override IConfiguration CreateConfiguration() 20 | { 21 | _tempFolder = new TemporaryFolder(); 22 | var connectionString = @"Data Source=" + _tempFolder.Folder + "yessql.db;Cache=Shared"; 23 | 24 | return new Configuration() 25 | .UseSqLite(connectionString) 26 | .SetTablePrefix(TablePrefix) 27 | .UseDefaultIdGenerator() 28 | .SetIdentityColumnSize(IdentityColumnSize.Int32) 29 | ; 30 | } 31 | 32 | [Fact(Skip = "Skip to make test faster in this configuration")] 33 | public override Task ShouldGateQuery() 34 | { 35 | return base.ShouldGateQuery(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/YesSql.Tests/TemporaryFolder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace YesSql.Tests 5 | { 6 | public class TemporaryFolder : IDisposable 7 | { 8 | private readonly bool _deleteOnDispose; 9 | 10 | public TemporaryFolder(bool deleteOnDispose = true) 11 | { 12 | Folder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 13 | _deleteOnDispose = deleteOnDispose; 14 | } 15 | 16 | public string Folder { get; } 17 | 18 | public void Dispose() 19 | { 20 | if (_deleteOnDispose) 21 | { 22 | if (Directory.Exists(Folder)) 23 | { 24 | Directory.Delete(Folder, true); 25 | } 26 | } 27 | } 28 | 29 | public override string ToString() 30 | { 31 | return Folder; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/YesSql.Tests/TestLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Text; 4 | 5 | namespace YesSql.Tests 6 | { 7 | public class TestLogger : ILogger 8 | { 9 | private object _lockObj = new object(); 10 | 11 | private readonly StringBuilder _builder; 12 | 13 | public TestLogger(StringBuilder builder = null) 14 | { 15 | _builder = builder ?? new StringBuilder(); 16 | } 17 | 18 | public IDisposable BeginScope(TState state) 19 | { 20 | return new FakeScope(); 21 | } 22 | 23 | public bool IsEnabled(LogLevel logLevel) 24 | { 25 | return IsLevelEnabled(logLevel); 26 | } 27 | 28 | public bool IsLevelEnabled(LogLevel logLevel) 29 | { 30 | return true; 31 | } 32 | 33 | public void Log(LogLevel logLevel, string log) 34 | { 35 | lock (_lockObj) 36 | { 37 | _builder.AppendLine(logLevel.ToString().ToUpper() + ": " + log); 38 | } 39 | } 40 | 41 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) 42 | { 43 | Log(logLevel, formatter(state, exception)); 44 | } 45 | 46 | public override string ToString() 47 | { 48 | lock (_lockObj) 49 | { 50 | return _builder.ToString(); 51 | } 52 | } 53 | } 54 | 55 | public class FakeScope : IDisposable 56 | { 57 | public void Dispose() 58 | { 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/YesSql.Tests/YesSql.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net8.0 5 | latest 6 | YesSql.Tests 7 | YesSql.Tests 8 | true 9 | false 10 | false 11 | false 12 | false 13 | false 14 | false 15 | false 16 | false 17 | true 18 | ../../src/YesSqlKey.snk 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | all 31 | runtime; build; native; contentfiles; analyzers 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | PreserveNewest 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /test/YesSql.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method" 3 | } 4 | --------------------------------------------------------------------------------