├── .github └── FUNDING.yml ├── .gitignore ├── .vs └── DatabaseWrapper │ └── v14 │ └── .suo ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DONATIONS.md ├── LICENSE.md ├── README.md ├── assets ├── icon.ico ├── icon.png └── icon.pptx └── src ├── DatabaseWrapper.Core ├── Column.cs ├── DataTypeEnum.cs ├── DatabaseClientBase.cs ├── DatabaseHelperBase.cs ├── DatabaseQueryEvent.cs ├── DatabaseSettings.cs ├── DatabaseWrapper.Core.csproj ├── DatabaseWrapper.Core.xml ├── DbTypeEnum.cs ├── Helper.cs ├── LICENSE.md ├── OrderDirectionEnum.cs ├── ResultOrder.cs └── assets │ ├── icon.ico │ └── icon.png ├── DatabaseWrapper.Mysql ├── DatabaseClient.cs ├── DatabaseWrapper.Core.xml ├── DatabaseWrapper.Mysql.csproj ├── DatabaseWrapper.Mysql.xml ├── LICENSE.md ├── MysqlHelper.cs └── assets │ ├── icon.ico │ └── icon.png ├── DatabaseWrapper.Oracle ├── DatabaseClient.cs ├── DatabaseWrapper.Core.xml ├── DatabaseWrapper.Oracle.csproj ├── DatabaseWrapper.Oracle.xml ├── LICENSE.md ├── OracleHelper.cs └── assets │ ├── icon.ico │ └── icon.png ├── DatabaseWrapper.Postgresql ├── DatabaseClient.cs ├── DatabaseWrapper.Core.xml ├── DatabaseWrapper.Postgresql.csproj ├── DatabaseWrapper.Postgresql.xml ├── LICENSE.md ├── PostgresqlHelper.cs └── assets │ ├── icon.ico │ └── icon.png ├── DatabaseWrapper.SqlServer ├── DatabaseClient.cs ├── DatabaseWrapper.Core.xml ├── DatabaseWrapper.SqlServer.csproj ├── DatabaseWrapper.SqlServer.xml ├── LICENSE.md ├── SqlServerHelper.cs └── assets │ ├── icon.ico │ └── icon.png ├── DatabaseWrapper.Sqlite ├── DatabaseClient.cs ├── DatabaseWrapper.Core.xml ├── DatabaseWrapper.Sqlite.csproj ├── DatabaseWrapper.Sqlite.xml ├── LICENSE.md ├── SqliteHelper.cs └── assets │ ├── icon.ico │ └── icon.png ├── DatabaseWrapper.sln ├── DatabaseWrapper ├── DatabaseClient.cs ├── DatabaseWrapper.Core.xml ├── DatabaseWrapper.csproj ├── DatabaseWrapper.xml ├── LICENSE.md └── assets │ ├── icon.ico │ └── icon.png ├── Test.Async ├── Program.cs ├── Test.Async.csproj └── headshot.png ├── Test.DatabaseConsole ├── Program.cs └── Test.DatabaseConsole.csproj ├── Test.DatabaseConsoleAsync ├── Program.cs └── Test.DatabaseConsoleAsync.csproj ├── Test.Mysql ├── Program.cs ├── Test.Mysql.csproj └── headshot.png ├── Test.MysqlAsync ├── Program.cs ├── Test.MysqlAsync.csproj └── headshot.png ├── Test.NuGet ├── Program.cs ├── Test.NuGet.csproj └── headshot.png ├── Test.NuGetAsync ├── Program.cs ├── Test.NuGetAsync.csproj └── headshot.png ├── Test.Oracle ├── Program.cs ├── Test.Oracle.csproj └── headshot.png ├── Test.Postgresql ├── Program.cs ├── Test.Postgresql.csproj └── headshot.png ├── Test.PostgresqlAsync ├── Program.cs ├── Test.PostgresqlAsync.csproj └── headshot.png ├── Test.SqlServer ├── Program.cs ├── Test.SqlServer.csproj └── headshot.png ├── Test.SqlServerAsync ├── Program.cs ├── Test.SqlServerAsync.csproj └── headshot.png ├── Test.Sqlite ├── Program.cs ├── Test.Sqlite.csproj └── headshot.png ├── Test.SqliteAsync ├── Program.cs ├── Test.SqliteAsync.csproj └── headshot.png └── Test ├── Program.cs ├── Test.csproj └── headshot.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [jchristn] 2 | custom: ["https://paypal.me/joelchristner"] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | *.snk 10 | 11 | # User-specific files (MonoDevelop/Xamarin Studio) 12 | *.userprefs 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | project.fragment.lock.json 47 | artifacts/ 48 | 49 | *_i.c 50 | *_p.c 51 | *_i.h 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.tmp_proj 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | *.pidb 71 | *.svclog 72 | *.scc 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # Visual Studio code coverage results 115 | *.coverage 116 | *.coveragexml 117 | 118 | # NCrunch 119 | _NCrunch_* 120 | .*crunch*.local.xml 121 | nCrunchTemp_* 122 | 123 | # MightyMoose 124 | *.mm.* 125 | AutoTest.Net/ 126 | 127 | # Web workbench (sass) 128 | .sass-cache/ 129 | 130 | # Installshield output folder 131 | [Ee]xpress/ 132 | 133 | # DocProject is a documentation generator add-in 134 | DocProject/buildhelp/ 135 | DocProject/Help/*.HxT 136 | DocProject/Help/*.HxC 137 | DocProject/Help/*.hhc 138 | DocProject/Help/*.hhk 139 | DocProject/Help/*.hhp 140 | DocProject/Help/Html2 141 | DocProject/Help/html 142 | 143 | # Click-Once directory 144 | publish/ 145 | 146 | # Publish Web Output 147 | *.[Pp]ublish.xml 148 | *.azurePubxml 149 | # TODO: Comment the next line if you want to checkin your web deploy settings 150 | # but database connection strings (with potential passwords) will be unencrypted 151 | *.pubxml 152 | *.publishproj 153 | 154 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 155 | # checkin your Azure Web App publish settings, but sensitive information contained 156 | # in these scripts will be unencrypted 157 | PublishScripts/ 158 | 159 | # NuGet Packages 160 | *.nupkg 161 | # The packages folder can be ignored because of Package Restore 162 | **/packages/* 163 | # except build/, which is used as an MSBuild target. 164 | !**/packages/build/ 165 | # Uncomment if necessary however generally it will be regenerated when needed 166 | #!**/packages/repositories.config 167 | # NuGet v3's project.json files produces more ignoreable files 168 | *.nuget.props 169 | *.nuget.targets 170 | 171 | # Microsoft Azure Build Output 172 | csx/ 173 | *.build.csdef 174 | 175 | # Microsoft Azure Emulator 176 | ecf/ 177 | rcf/ 178 | 179 | # Windows Store app package directories and files 180 | AppPackages/ 181 | BundleArtifacts/ 182 | Package.StoreAssociation.xml 183 | _pkginfo.txt 184 | 185 | # Visual Studio cache files 186 | # files ending in .cache can be ignored 187 | *.[Cc]ache 188 | # but keep track of directories ending in .cache 189 | !*.[Cc]ache/ 190 | 191 | # Others 192 | ClientBin/ 193 | ~$* 194 | *~ 195 | *.dbmdl 196 | *.dbproj.schemaview 197 | *.jfm 198 | *.pfx 199 | *.publishsettings 200 | node_modules/ 201 | orleans.codegen.cs 202 | 203 | # Since there are multiple workflows, uncomment next line to ignore bower_components 204 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 205 | #bower_components/ 206 | 207 | # RIA/Silverlight projects 208 | Generated_Code/ 209 | 210 | # Backup & report files from converting an old project file 211 | # to a newer Visual Studio version. Backup files are not needed, 212 | # because we have git ;-) 213 | _UpgradeReport_Files/ 214 | Backup*/ 215 | UpgradeLog*.XML 216 | UpgradeLog*.htm 217 | 218 | # SQL Server files 219 | *.mdf 220 | *.ldf 221 | 222 | # Business Intelligence projects 223 | *.rdl.data 224 | *.bim.layout 225 | *.bim_*.settings 226 | 227 | # Microsoft Fakes 228 | FakesAssemblies/ 229 | 230 | # GhostDoc plugin setting file 231 | *.GhostDoc.xml 232 | 233 | # Node.js Tools for Visual Studio 234 | .ntvs_analysis.dat 235 | 236 | # Visual Studio 6 build log 237 | *.plg 238 | 239 | # Visual Studio 6 workspace options file 240 | *.opt 241 | 242 | # Visual Studio LightSwitch build output 243 | **/*.HTMLClient/GeneratedArtifacts 244 | **/*.DesktopClient/GeneratedArtifacts 245 | **/*.DesktopClient/ModelManifest.xml 246 | **/*.Server/GeneratedArtifacts 247 | **/*.Server/ModelManifest.xml 248 | _Pvt_Extensions 249 | 250 | # Paket dependency manager 251 | .paket/paket.exe 252 | paket-files/ 253 | 254 | # FAKE - F# Make 255 | .fake/ 256 | 257 | # JetBrains Rider 258 | .idea/ 259 | *.sln.iml 260 | 261 | # CodeRush 262 | .cr/ 263 | 264 | # Python Tools for Visual Studio (PTVS) 265 | __pycache__/ 266 | *.pyc 267 | 268 | # Cake - Uncomment if you are using it 269 | # tools/ 270 | 271 | -------------------------------------------------------------------------------- /.vs/DatabaseWrapper/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/.vs/DatabaseWrapper/v14/.suo -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Current Version 4 | 5 | v6.x 6 | 7 | - Oracle support (thank you @Skimmenthal13) 8 | - Asynchronous APIs 9 | - Updated dependencies 10 | - Bugfixes 11 | - Minor breaking changes (API name changes) 12 | 13 | ## Previous Versions 14 | 15 | v5.0.x 16 | 17 | - Breaking changes (class and enum name changes) 18 | - Major internal refactor, code cleanup, and consistency 19 | - Event handler for query results 20 | - Abstract classes and implementations for for database-specific helpers and clients 21 | - Support for GUID type 22 | - More consistency in test projects 23 | - Bugfixes, retargeting to include .NET Framework 4.8 and .NET 7.0 24 | 25 | v4.1.x 26 | 27 | - Minor breaking changes 28 | - Moved debug settings and logger into ```DatabaseSettings``` 29 | - Dependency updates 30 | - Validated support for MariaDB 31 | 32 | v4.0.0 33 | 34 | - Breaking changes 35 | - Internal refactor 36 | - Use of external library ```ExpressionTree``` for ```Expr``` class, replaces ```Expression``` class 37 | - Use of external library ```ExpressionTree``` for ```OperatorEnum``` class, replaces ```Operator``` enum 38 | - ```Expression.LeftTerm``` is now ```Expr.Left``` 39 | - ```Expression.RightTerm``` is now ```Expr.Right``` 40 | - Reduced dependency clutter 41 | 42 | v3.3.2 43 | 44 | - Support for BLOB data types using ```byte[]``` 45 | - SQL Server: ```varbinary(max)``` 46 | - Sqlite: ```blob``` 47 | - Postgresql: ```bytea``` 48 | - Mysql: ```longblob``` 49 | 50 | v3.3.0 51 | 52 | - Breaking change: update and insert will now correctly set values to ```null``` 53 | - Minor refactor to SQL query builders 54 | - Better support for DateTimeOffset 55 | 56 | v3.2.0 57 | 58 | - New APIs: Sum, Count, Exists 59 | 60 | v3.1.0 61 | 62 | - Breaking change: removal of .NET Framework and upgrade to .NET standard 2.1 63 | - DatabaseSettings class 64 | - New constructors 65 | 66 | v3.0.1.2 67 | 68 | - Migrate to Microsoft.Data.Sqlite for DatabaseWrapper.Sqlite 69 | 70 | v3.0.1 71 | 72 | - Support for 'Between' operator (thank you @twobytescy) 73 | 74 | v3.0.0 75 | 76 | - Major refactor, minor breaking changes 77 | - Broke apart DatabaseWrapper into several database-specific projects; DatabaseWrapper itself can still target any 78 | 79 | v2.0.5 80 | 81 | - Added COLLATE NOCASE to Sqlite TEXT column creation 82 | 83 | v2.0.4 84 | 85 | - Truncate table fix 86 | 87 | v2.0.3 88 | 89 | - String names for serialized enum members 90 | 91 | v2.0.2 92 | 93 | - Fix Sqlite field name encapsulation character 94 | 95 | v2.0.1 96 | 97 | - Change Sqlite timestamp fields from NUMERIC to TEXT 98 | 99 | v2.0.0 100 | 101 | - Support for Sqlite (.NET Framework 4.6.1 and Sqlite seems to have issues, but .NET Core works well) 102 | - For Microsoft SQL Server, MySQL, and PostgreSQL, use the original full constructors 103 | - For Sqlite, use the simplified constructor ```DatabaseClient(string filename)``` 104 | - Update dependencies (and update minimum .NET Framework required to .NET Framework 4.6.1) 105 | 106 | v1.5.1 107 | 108 | - INSERT fix for MySQL 109 | 110 | v1.5.0 111 | 112 | - Breaking changes; improved logging setup 113 | 114 | v1.4.7 115 | 116 | - Fix bug with describing a table returning redundant rows 117 | 118 | v1.4.5 119 | 120 | - XML documentation 121 | 122 | v1.4.x 123 | 124 | - Expose ```Type``` property in ```DatabaseClient``` 125 | - Encapsulate table names in queries with the appropriate characters 126 | - Microsoft SQL: ``` [tablename] ``` 127 | - MySQL: ``` `tablename` ``` 128 | - PostgreSQL: ``` "tablename" ``` 129 | - Add support for CreateTable and DropTable operations, please note the following constraints: 130 | - For PostgreSQL, automatically uses ```SERIAL PRIMARY KEY``` for primary keys 131 | - For Microsoft SQL, automatically creates a constraint and assumes primary key type is ```int``` 132 | - For Microsoft SQL, DateTime types are created as ```datetime2``` 133 | - For MySQL, automatically applies ```AUTO_INCREMENT``` to primary keys 134 | - For MySQL, assumes ```Engine=InnoDB``` and ```AUTO_INCREMENT=1``` 135 | - For a full list of supported data types and how they are cast, please refer to: 136 | - ```DataType.cs```, and 137 | - ```DataTypeFromString``` method in ```DatabaseClient.cs``` 138 | 139 | v1.3.x 140 | 141 | - Rework of MSSQL SELECT with pagination, now requires ORDER BY clause to be set (breaking change) 142 | - Long-lived connections (rather than re-opening per query) 143 | - IDisposable support 144 | 145 | v1.2.x 146 | 147 | - Retarget to support both .NET Core 2.0 and .NET Framework 4.5.2. 148 | - Exposed SanitizeString through DatabaseClient 149 | - New signatures for PrependAnd and PrependOr to make use easier 150 | - PostgreSQL support 151 | - Minor refactor 152 | 153 | v1.1.x 154 | 155 | - Added Trunate API 156 | - Simplified (new) constructor for Expression 157 | - Additional Helper static methods to convert DataTable to useful objects (List, Dictionary, List, dynamic) 158 | - Instance method to create timestamp for the given database type. 159 | - Support for string for database type in timestamp and where clause builders 160 | - New constructor using string for dbtype instead of enum 161 | - Raw query support 162 | - Pagination support in SELECT queries: use indexStart, maxResults, and orderByClause (all are required) 163 | - Numerous bugfixes 164 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 44 | 45 | For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing! 4 | 5 | The following is a set of guidelines for contributing to our project on Github. These are mostly guidelines, not rules. 6 | 7 | ## Code of Conduct 8 | 9 | This project and everyone participating in it is governed by the Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to project moderators. 10 | 11 | ## Pull Requests 12 | 13 | Please follow these guidelines when submitting pull requests (PRs): 14 | 15 | - PRs should be manageable in size to make it easy for us to validate and integrate 16 | - Each PR should be contained to a single fix or a single feature 17 | - Describe the motivation for the PR 18 | - Describe a methodology to test and validate, if appropriate 19 | 20 | Please ensure that the code in your PR follows a style similar to that of the project. If you find a material discrepancy between the style followed by the project and a de facto standard style given the project language and framework, please let us know so we can amend and make our code more maintainable. 21 | 22 | ## Asking Questions 23 | 24 | Prior to asking questions, please review closed issues and wiki pages. If your question is not answered in either of those places, please feel free to file an issue! This will also help us to build out documentation. 25 | 26 | ## Reporting Bugs 27 | 28 | If you encounter an issue, please let us know! We kindly ask that you supply the following information with your bug report when you file an issue. Feel free to copy/paste from the below and use as a template. 29 | 30 | --- Bug Report --- 31 | 32 | Operating system and version: Windows 10 33 | Framework and runtime: .NET Core 2.0 34 | Issue encountered: The widget shifted left 35 | Expected behavior: The widget should have shifted right 36 | Steps to reproduce: Instantiate the widget and call .ShiftRight() 37 | Sample code encapsulating the problem: 38 | ``` 39 | Widget widget = new Widget(); 40 | widget.ShiftRight(); 41 | ``` 42 | Exception details: [insert exception output here] 43 | Stack trace: [if appropriate] 44 | 45 | --- End --- 46 | 47 | ## Suggesting Enhancements 48 | 49 | Should there be a way that you feel we could improve upon this project, please feel free to file an issue and use the template below to provide the necessary details to support the request. 50 | 51 | Some basic guidelines for suggesting enhancements: 52 | 53 | - Use a clear and descriptive title for the issue to identify the suggestion. 54 | - Provide a step-by-step description of the suggested enhancement in as many details as possible. 55 | - Provide specific examples to demonstrate the steps including copy/pasteable snippets where possible 56 | - Describe the current behavior and the behavior you would like to see 57 | - Describe the usefulness of the enhancement to yourself and potentially to others 58 | 59 | --- Enhancement Request --- 60 | 61 | Enhancement request title: Widgets should have a color attribute 62 | Use case: I want to specify what color a widget is 63 | Current behavior: Widgets don't have a color 64 | Requested behavior: Allow me to specify a widget's color 65 | Recommended implementation: Add a Color attribute to the Widget class 66 | Usefulness of the enhancement: All widgets have color, and everyone has to build their own implementation to set this 67 | 68 | --- End --- 69 | -------------------------------------------------------------------------------- /DONATIONS.md: -------------------------------------------------------------------------------- 1 | ## Donations 2 | 3 | If you're interested in financially supporting this work on other open source projects I manage, first of all, thank you! It brings me delight to know that this software has helped you in some way. Please find below address details for donations using 4 | 5 | ### Traditional 6 | 7 | | Method | Address | 8 | |--------|---------| 9 | | PayPal | @joelchristner - https://paypal.me/joelchristner?country.x=US&locale.x=en_US | 10 | | Venmo | @Joel-Christner - https://account.venmo.com/u/Joel-Christner | 11 | 12 | ### Cryptocurrency (Mainstream) 13 | 14 | | Method | Address | 15 | |----------|---------| 16 | | Bitcoin | 3HRgnvEWQBDdWDp75CFDsz3PirCYmftDwU | 17 | | Ethereum | 0xE064dC84270e17e2Ac34b2552461d672BdBC5e36 | 18 | 19 | ### Cryptocurrency (Altcoins) 20 | 21 | | Method | Address | 22 | |--------|---------| 23 | | XRP | Tag 1765608084 Address rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg | 24 | | Shiba Inu SHIB | 0xdA58D4ba0d5823d80a0C42C69E139124B889c69a | 25 | | Algorand ALGO | FFKA23KC4BHEU5HM4OQHLEILVIYDLRXYK6WD6UI573JPUGHZR43JVHAF7A | 26 | | Stellar Lumens XML | Memo 2264929895 Address GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOKY3B2WSQHG4W37 | 27 | | Dogecoin DOGE | DQ2dn4UifpYA8RyuNF1t112Y1XH5L42Rxv | 28 | | Cardano ADA | addr1vxrxyrv0phgr2xcl08dj0sfy425mhqehuu4dy99ja4nhtwqfsvgjk | 29 | 30 | If you have a coin you prefer to use, please let me know! 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DatabaseWrapper 2 | 3 | | Library | Version | Downloads | 4 | |---|---|---| 5 | | DatabaseWrapper (all supported database types) | [![NuGet Version](https://img.shields.io/nuget/v/DatabaseWrapper.svg?style=flat)](https://www.nuget.org/packages/DatabaseWrapper/) | [![NuGet](https://img.shields.io/nuget/dt/DatabaseWrapper.svg)](https://www.nuget.org/packages/DatabaseWrapper) | 6 | | DatabaseWrapper.Mysql | [![NuGet Version](https://img.shields.io/nuget/v/DatabaseWrapper.Mysql.svg?style=flat)](https://www.nuget.org/packages/DatabaseWrapper.Mysql/) | [![NuGet](https://img.shields.io/nuget/dt/DatabaseWrapper.Mysql.svg)](https://www.nuget.org/packages/DatabaseWrapper.Mysql) | 7 | | DatabaseWrapper.Postgresql | [![NuGet Version](https://img.shields.io/nuget/v/DatabaseWrapper.Postgresql.svg?style=flat)](https://www.nuget.org/packages/DatabaseWrapper.Postgresql/) | [![NuGet](https://img.shields.io/nuget/dt/DatabaseWrapper.Postgresql.svg)](https://www.nuget.org/packages/DatabaseWrapper.Postgresql) | 8 | | DatabaseWrapper.Sqlite | [![NuGet Version](https://img.shields.io/nuget/v/DatabaseWrapper.Sqlite.svg?style=flat)](https://www.nuget.org/packages/DatabaseWrapper.Sqlite/) | [![NuGet](https://img.shields.io/nuget/dt/DatabaseWrapper.Sqlite.svg)](https://www.nuget.org/packages/DatabaseWrapper.Sqlite) | 9 | | DatabaseWrapper.SqlServer | [![NuGet Version](https://img.shields.io/nuget/v/DatabaseWrapper.SqlServer.svg?style=flat)](https://www.nuget.org/packages/DatabaseWrapper.SqlServer/) | [![NuGet](https://img.shields.io/nuget/dt/DatabaseWrapper.SqlServer.svg)](https://www.nuget.org/packages/DatabaseWrapper.SqlServer) | 10 | | DatabaseWrapper.Core | [![NuGet Version](https://img.shields.io/nuget/v/DatabaseWrapper.Core.svg?style=flat)](https://www.nuget.org/packages/DatabaseWrapper.Core/) | [![NuGet](https://img.shields.io/nuget/dt/DatabaseWrapper.Core.svg)](https://www.nuget.org/packages/DatabaseWrapper.Core) | 11 | | ExpressionTree | [![NuGet Version](https://img.shields.io/nuget/v/ExpressionTree.svg?style=flat)](https://www.nuget.org/packages/ExpressionTree/) | [![NuGet](https://img.shields.io/nuget/dt/ExpressionTree.svg)](https://www.nuget.org/packages/ExpressionTree) | 12 | 13 | DatabaseWrapper is the EASIEST and FASTEST way to get a data-driven application up and running using SQL Server, MySQL, PostgreSQL, or Sqlite. 14 | 15 | For a sample app exercising this library, refer to the numerous ```Test``` projects contained within the solution. 16 | 17 | Core features: 18 | 19 | - Dynamic query building 20 | - Hierarchical Boolean logic using Expression objects 21 | - Support for SQL server native vs Windows authentication 22 | - Support for SELECT, INSERT, UPDATE, DELETE, TRUNCATE, CREATE, DROP or raw queries 23 | - Programmatic table creation and removal (drop) 24 | - Built-in sanitization 25 | - Support for .NET Standard, .NET Core, and .NET Framework 26 | - Support for SQL Server, Sqlite, PostgreSQL, MySQL, MariaDB, Oracle, both on-premises and in the cloud 27 | - Both synchronous and asynchronous APIs 28 | 29 | ## New in v6.x 30 | 31 | - Oracle support (thank you @Skimmenthal13) 32 | - Asynchronous APIs 33 | - Updated dependencies 34 | - Bugfixes 35 | - Minor breaking changes (API name changes) 36 | 37 | ## Special Thanks 38 | 39 | Special thanks to those who have helped contribute or otherwise improve the library! 40 | 41 | @shawty @constantinje @thedarklort @l-404-l @igrgurina @Vaelek @treyhay31 @daoye @twobytescy @rinkusahu1 @Skimmenthal13 42 | 43 | ## A Note on Sanitization 44 | 45 | Use of parameterized queries vs building queries dynamically is a sensitive subject. Proponents of parameterized queries have data on their side - that parameterization does the right thing to prevent SQL injection and other issues. *I do not disagree with them*. However, it is worth noting that with proper care, you CAN build systems that allow you to dynamically build queries, and you SHOULD do so as long as you build in the appropriate safeguards. 46 | 47 | If you find an injection attack that will defeat the sanitization layer built into this project, please let me know! 48 | 49 | ## Simple Example 50 | 51 | Refer to the test project for a more complete example with sample table setup scripts. 52 | ```csharp 53 | using DatabaseWrapper; 54 | using DatabaseWrapper.Core; 55 | using ExpressionTree; 56 | 57 | DatabaseClient client = null; 58 | 59 | // Sqlite 60 | client = new DatabaseClient("[databasefilename]"); 61 | 62 | // SQL Server, MySQL, or PostgreSQL 63 | client = new DatabaseClient(DbTypes.SqlServer, "[hostname]", [port], "[user]", "[password]", "[databasename]"); 64 | client = new DatabaseClient(DbTypes.Mysql, "[hostname]", [port], "[user]", "[password]", "[databasename]"); 65 | client = new DatabaseClient(DbTypes.Postgresql, "[hostname]", [port], "[user]", "[password]", "[databasename]"); 66 | 67 | // SQL Express 68 | client = new DatabaseClient(DbTypes.SqlServer, "[hostname]", [port], "[user]", "[password]", "[instance]", "[databasename]"); 69 | 70 | // some variables we'll be using 71 | Dictionary d; 72 | Expr e; 73 | List fields; 74 | DataTable result; 75 | 76 | // add a record 77 | d = new Dictionary(); 78 | d.Add("firstName", "Joel"); 79 | d.Add("lastName", "Christner"); 80 | d.Add("notes", "Author"); 81 | result = client.Insert("person", d); 82 | result = await client.InsertAsync("person", d); 83 | 84 | // update a record 85 | d = new Dictionary(); 86 | d.Add("notes", "The author :)"); 87 | e = new Expr("firstName", OperatorEnum.Equals, "Joel"); 88 | client.Update("person", d, e); 89 | await client.UpdateAsync("person", d, e); 90 | 91 | // retrieve 10 records 92 | fields = new List { "firstName", "lastName" }; // leave null for * 93 | e = new Expr("lastName", OperatorEnum.Equals, "Christner"); 94 | ResultOrder[] order = new ResultOrder[1]; 95 | order = new ResultOrder("firstName", OrderDirectionEnum.Ascending) 96 | result = client.Select("person", 0, 10, fields, e, order); 97 | result = await client.SelectAsync("person", 0, 10, fields, e, order); 98 | 99 | // delete a record 100 | e = new Expr("firstName", Operators.Equals, "Joel"); 101 | client.Delete("person", e); 102 | await client.DeleteAsync("person", e); 103 | 104 | // execute a raw query 105 | result = client.Query("SELECT customer_id FROM customer WHERE customer_id > 10"); 106 | result = await client.QueryAsync("SELECT customer_id FROM customer WHERE customer_id > 10"); 107 | ``` 108 | 109 | ## Sample Compound Expression 110 | 111 | Expressions, i.e. the ```Expr``` class from ```ExpressionTree```, can be nested in either the ```Left``` or ```Right``` properties. Conversion from ```Expr``` to a WHERE clause uses recursion, so you have a good degree of flexibility in building your expressions in terms of depth. 112 | 113 | ```csharp 114 | Expr e = new Expr { 115 | Left = new Expr("age", OperatorEnum.GreaterThan, 30), 116 | Operator = Operators.And, 117 | Right = new Expr("height", OperatorEnum.LessThan, 74) 118 | }; 119 | ``` 120 | 121 | ## Select with Pagination 122 | 123 | Use ```IndexStart```, ```MaxResults```, and ```ResultOrder[]``` to retrieve paginated results. The query will retrieve maxResults records starting at row number indexStart using an ordering based on orderByClause. See the example in the DatabaseWrapperTest project. 124 | 125 | IMPORTANT: When doing pagination with SQL Server, you MUST specify an ```ResultOrder[]```. 126 | 127 | ```csharp 128 | ResultOrder[] order = new ResultOrder[1]; 129 | order = new ResultOrder("firstName", OrderDirectionEnum.Ascending); 130 | DataTable result = client.Select("person", 5, 10, null, e, order); 131 | ``` 132 | 133 | ## Need a Timestamp? 134 | 135 | We added a simple static method for this which you can use when building expressions (or elsewhere). An object method exists as well. 136 | 137 | ```csharp 138 | string ts = client.Timestamp(DateTime.Now); 139 | // 08/23/2016 05:34:32.4349034 PM 140 | 141 | string tso = client.Timestamp(DateTime.Now); 142 | // 2016-08-23 17:34:32.446913 143 | ``` 144 | 145 | ## Other Notes 146 | 147 | ### General 148 | 149 | When using database-specific classes ```DatabaseWrapper.Mysql```, ```DatabaseWrapper.Postgresql```, ```DatabaseWrapper.SqlServer```, or ```DatabaseWrapper.Sqlite```, the constructor is simplified from what is shown above. 150 | 151 | For Sqlite: 152 | 153 | ```csharp 154 | DatabaseClient client = new DatabaseClient("[databasefilename]"); 155 | ``` 156 | 157 | For SQL Server, MySQL, or PostgreSQL: 158 | 159 | ```csharp 160 | DatabaseClient client = new DatabaseClient(DbTypes.SqlServer, "[hostname]", [port], "[user]", "[password]", "[databasename]"); 161 | DatabaseClient client = new DatabaseClient(DbTypes.Mysql, "[hostname]", [port], "[user]", "[password]", "[databasename]"); 162 | DatabaseClient client = new DatabaseClient(DbTypes.Postgresql, "[hostname]", [port], "[user]", "[password]", "[databasename]"); 163 | ``` 164 | 165 | For SQL Server Express: 166 | 167 | ```csharp 168 | DatabaseClient client = new DatabaseClient(DbTypes.SqlServer, "[hostname]", [port], "[user]", "[password]", "[instance]", "[databasename]"); 169 | ``` 170 | 171 | ### MySQL 172 | 173 | - MySQL does not like to return updated rows. I thought about making the UPDATE clause require that you supply the ID field and the ID value so that I could retrieve it after the fact, but that approach is just too limiting. 174 | 175 | ### MariaDB 176 | 177 | - Use the MySQL constructor. MySQL constraints remain. 178 | 179 | ### PostgreSQL 180 | 181 | - Cleansing of strings in PostgreSQL uses the dollar-quote style. Fieldnames are always encapsulated in double-quotes for PostgreSQL. 182 | 183 | ### SQL Server 184 | 185 | - Pagination where ```IndexStart``` and ```MaxResults``` are supplied demands use of ```ResultOrder[]```. 186 | 187 | ### Sqlite 188 | 189 | - Sqlite may not work out of the box with .NET Framework. In order to use Sqlite with .NET Framework, you'll need to manually copy the ```runtimes``` folder into your project output directory. This directory is automatically created when building for .NET Core. To get this folder, build the ```Test.Sqlite``` project and navigate to the ```bin/debug/netcoreapp*``` directory. Then copy the ```runtimes``` folder into the project output directory of your .NET Framework application. 190 | 191 | ## Version history 192 | 193 | Refer to CHANGELOG.md. 194 | -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/assets/icon.ico -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/assets/icon.png -------------------------------------------------------------------------------- /assets/icon.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/assets/icon.pptx -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/Column.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | /// 10 | /// Database table column. 11 | /// 12 | public class Column 13 | { 14 | #region Public-Members 15 | 16 | /// 17 | /// The name of the column. 18 | /// 19 | public string Name = null; 20 | 21 | /// 22 | /// Whether or not the column is the table's primary key. 23 | /// 24 | public bool PrimaryKey = false; 25 | 26 | /// 27 | /// The data type of the column. 28 | /// 29 | public DataTypeEnum Type = DataTypeEnum.Varchar; 30 | 31 | /// 32 | /// The maximum character length of the data contained within the column. 33 | /// 34 | public int? MaxLength = null; 35 | 36 | /// 37 | /// For precision, i.e. number of places after the decimal. 38 | /// 39 | public int? Precision = null; 40 | 41 | /// 42 | /// Whether or not the column can contain NULL. 43 | /// 44 | public bool Nullable = true; 45 | 46 | #endregion 47 | 48 | #region Private-Members 49 | 50 | private List _RequiresLengthAndPrecision = new List 51 | { 52 | DataTypeEnum.Decimal, 53 | DataTypeEnum.Double 54 | }; 55 | 56 | private List _RequiresLength = new List 57 | { 58 | DataTypeEnum.Nvarchar, 59 | DataTypeEnum.Varchar 60 | }; 61 | 62 | #endregion 63 | 64 | #region Constructors-and-Factories 65 | 66 | /// 67 | /// Instantiate the object. 68 | /// 69 | public Column() 70 | { 71 | } 72 | 73 | /// 74 | /// Instantiate the object. 75 | /// 76 | /// Name of the column. 77 | /// Indicate if this column is the primary key. 78 | /// DataType for the column. 79 | /// Indicate if this column is nullable. 80 | public Column(string name, bool primaryKey, DataTypeEnum dt, bool nullable) 81 | { 82 | if (String.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); 83 | if (primaryKey && nullable) throw new ArgumentException("Primary key column '" + name + "' cannot be nullable."); 84 | 85 | Name = name; 86 | PrimaryKey = primaryKey; 87 | Type = dt; 88 | Nullable = nullable; 89 | 90 | if (_RequiresLengthAndPrecision.Contains(dt)) 91 | { 92 | throw new ArgumentException("Column '" + name + "' must include both maximum length and precision; use the constructor that allows these values to be specified."); 93 | } 94 | 95 | if (_RequiresLength.Contains(dt)) 96 | { 97 | throw new ArgumentException("Column '" + name + "' must include a maximum length; use the constructor that allows these values to be specified."); 98 | } 99 | } 100 | 101 | /// 102 | /// Instantiate the object. 103 | /// 104 | /// Name of the column. 105 | /// Indicate if this column is the primary key. 106 | /// DataType for the column. 107 | /// Max length for the column. 108 | /// Precision for the column. 109 | /// Indicate if this column is nullable. 110 | public Column(string name, bool primaryKey, DataTypeEnum dt, int? maxLen, int? precision, bool nullable) 111 | { 112 | if (String.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); 113 | if (primaryKey && nullable) throw new ArgumentException("Primary key column '" + name + "' cannot be nullable."); 114 | if (maxLen != null && maxLen < 1) throw new ArgumentException("Column '" + name + "' maximum length must be greater than zero if not null."); 115 | if (precision != null && precision < 1) throw new ArgumentException("Column '" + name + "' preicision must be greater than zero if not null."); 116 | 117 | Name = name; 118 | PrimaryKey = primaryKey; 119 | Type = dt; 120 | MaxLength = maxLen; 121 | Precision = precision; 122 | Nullable = nullable; 123 | 124 | if (_RequiresLengthAndPrecision.Contains(dt)) 125 | { 126 | if (maxLen == null || precision == null || maxLen < 1 || precision < 1) 127 | { 128 | throw new ArgumentException("Column '" + name + "' must include both maximum length and precision, and both must be greater than zero."); 129 | } 130 | } 131 | 132 | if (_RequiresLength.Contains(dt)) 133 | { 134 | if (maxLen == null || maxLen < 1) 135 | { 136 | throw new ArgumentException("Column '" + name + "' must include a maximum length, and both must be greater than zero."); 137 | } 138 | } 139 | } 140 | 141 | #endregion 142 | 143 | #region Public-Methods 144 | 145 | /// 146 | /// Produce a human-readable string of the object. 147 | /// 148 | /// String. 149 | public override string ToString() 150 | { 151 | string ret = 152 | " [Column " + Name + "] "; 153 | 154 | if (PrimaryKey) ret += "PK "; 155 | ret += "Type: " + Type.ToString() + " "; 156 | if (MaxLength != null) ret += "MaxLen: " + MaxLength + " "; 157 | if (Precision != null) ret += "Precision: " + Precision + " "; 158 | ret += "Nullable: " + Nullable; 159 | 160 | return ret; 161 | } 162 | 163 | #endregion 164 | 165 | #region Private-Methods 166 | 167 | #endregion 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/DataTypeEnum.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Runtime.Serialization; 9 | 10 | /// 11 | /// Type of data contained in the column. 12 | /// 13 | public enum DataTypeEnum 14 | { 15 | /// 16 | /// Variable-length character. 17 | /// 18 | [EnumMember(Value = "Varchar")] 19 | Varchar, 20 | /// 21 | /// Variable-length unicode character. 22 | /// 23 | [EnumMember(Value = "Nvarchar")] 24 | Nvarchar, 25 | /// 26 | /// Tiny integer. 27 | /// 28 | [EnumMember(Value = "TinyInt")] 29 | TinyInt, 30 | /// 31 | /// Integer. 32 | /// 33 | [EnumMember(Value = "Int")] 34 | Int, 35 | /// 36 | /// Long 37 | /// 38 | [EnumMember(Value = "Long")] 39 | Long, 40 | /// 41 | /// Decimal 42 | /// 43 | [EnumMember(Value = "Decimal")] 44 | Decimal, 45 | /// 46 | /// Double 47 | /// 48 | [EnumMember(Value = "Double")] 49 | Double, 50 | /// 51 | /// Timestamp 52 | /// 53 | [EnumMember(Value = "DateTime")] 54 | DateTime, 55 | /// 56 | /// Timestamp with offset. 57 | /// 58 | [EnumMember(Value = "DateTimeOffset")] 59 | DateTimeOffset, 60 | /// 61 | /// Blob 62 | /// 63 | [EnumMember(Value = "Blob")] 64 | Blob, 65 | /// 66 | /// GUID. 67 | /// 68 | [EnumMember(Value = "Guid")] 69 | Guid, 70 | /// 71 | /// Boolean. 72 | /// 73 | [EnumMember(Value = "Boolean")] 74 | Boolean, 75 | /// 76 | /// Unknown 77 | /// 78 | [EnumMember(Value = "Unknown")] 79 | Unknown 80 | } 81 | } -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/DatabaseHelperBase.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using ExpressionTree; 7 | 8 | /// 9 | /// Base implementation of helper properties and methods. 10 | /// 11 | public abstract class DatabaseHelperBase 12 | { 13 | #region Public-Members 14 | 15 | /// 16 | /// Timestamp format for use in DateTime.ToString([format]). 17 | /// 18 | public string TimestampFormat; 19 | 20 | /// 21 | /// Timestamp offset format for use in DateTimeOffset.ToString([format]). 22 | /// 23 | public string TimestampOffsetFormat; 24 | 25 | #endregion 26 | 27 | #region Private-Members 28 | 29 | #endregion 30 | 31 | #region Constructors-and-Factories 32 | 33 | #endregion 34 | 35 | #region Public-Methods 36 | 37 | /// 38 | /// Build a connection string from DatabaseSettings. 39 | /// 40 | /// Settings. 41 | /// String. 42 | public abstract string GenerateConnectionString(DatabaseSettings settings); 43 | 44 | /// 45 | /// Query to retrieve the names of tables from a database. 46 | /// 47 | /// Database name. 48 | /// String. 49 | public abstract string RetrieveTableNamesQuery(string database); 50 | 51 | /// 52 | /// Query to retrieve the list of columns for a table. 53 | /// 54 | /// Database name. 55 | /// Table name. 56 | /// 57 | public abstract string RetrieveTableColumnsQuery(string database, string table); 58 | 59 | /// 60 | /// Method to sanitize a string. 61 | /// 62 | /// String. 63 | /// String. 64 | public abstract string SanitizeString(string val); 65 | 66 | /// 67 | /// Method to convert a Column object to the values used in a table create statement. 68 | /// 69 | /// Column. 70 | /// String. 71 | public abstract string ColumnToCreateQuery(Column col); 72 | 73 | /// 74 | /// Retrieve the primary key column from a list of columns. 75 | /// 76 | /// List of Column. 77 | /// Column. 78 | public abstract Column GetPrimaryKeyColumn(List columns); 79 | 80 | /// 81 | /// Retrieve a query used for table creation. 82 | /// 83 | /// Table name. 84 | /// List of columns. 85 | /// String. 86 | public abstract string CreateTableQuery(string tableName, List columns); 87 | 88 | /// 89 | /// Retrieve a query used for dropping a table. 90 | /// 91 | /// Table name. 92 | /// String. 93 | public abstract string DropTableQuery(string tableName); 94 | 95 | /// 96 | /// Retrieve a query used for selecting data from a table. 97 | /// 98 | /// Table name. 99 | /// Index start. 100 | /// Maximum number of results to retrieve. 101 | /// List of field names to return. 102 | /// Expression filter. 103 | /// Result order. 104 | /// String. 105 | public abstract string SelectQuery(string tableName, int? indexStart, int? maxResults, List returnFields, Expr filter, ResultOrder[] resultOrder); 106 | 107 | /// 108 | /// Retrieve a query used for inserting data into a table. 109 | /// 110 | /// The table in which you wish to INSERT. 111 | /// The key-value pairs for the row you wish to INSERT. 112 | /// String. 113 | public abstract string InsertQuery(string tableName, Dictionary keyValuePairs); 114 | 115 | /// 116 | /// Retrieve a query for inserting multiple rows into a table. 117 | /// 118 | /// The table in which you wish to INSERT. 119 | /// List of dictionaries containing key-value pairs for the rows you wish to INSERT. 120 | /// String. 121 | public abstract string InsertMultipleQuery(string tableName, List> keyValuePairList); 122 | 123 | /// 124 | /// Retrieve a query for updating data in a table. 125 | /// 126 | /// The table in which you wish to UPDATE. 127 | /// The key-value pairs for the data you wish to UPDATE. 128 | /// The expression containing the UPDATE filter (i.e. WHERE clause data). 129 | /// String. 130 | public abstract string UpdateQuery(string tableName, Dictionary keyValuePairs, Expr filter); 131 | 132 | /// 133 | /// Retrieve a query for deleting data from a table. 134 | /// 135 | /// Table name. 136 | /// Expression filter. 137 | /// String. 138 | public abstract string DeleteQuery(string tableName, Expr filter); 139 | 140 | /// 141 | /// Retrieve a query for truncating a table. 142 | /// 143 | /// Table name. 144 | /// String. 145 | public abstract string TruncateQuery(string tableName); 146 | 147 | /// 148 | /// Retrieve a query for determing whether data matching specified conditions exists. 149 | /// 150 | /// Table name. 151 | /// Expression filter. 152 | /// String. 153 | public abstract string ExistsQuery(string tableName, Expr filter); 154 | 155 | /// 156 | /// Retrieve a query that returns a count of the number of rows matching the supplied conditions. 157 | /// 158 | /// Table name. 159 | /// Column name to use to temporarily store the result. 160 | /// Expression filter. 161 | /// String. 162 | public abstract string CountQuery(string tableName, string countColumnName, Expr filter); 163 | 164 | /// 165 | /// Retrieve a query that sums the values found in the specified field. 166 | /// 167 | /// Table name. 168 | /// Column containing values to sum. 169 | /// Column name to temporarily store the result. 170 | /// Expression filter. 171 | /// String. 172 | public abstract string SumQuery(string tableName, string fieldName, string sumColumnName, Expr filter); 173 | 174 | /// 175 | /// Retrieve a timestamp in the database format. 176 | /// 177 | /// DateTime. 178 | /// String. 179 | public abstract string GenerateTimestamp(DateTime ts); 180 | 181 | /// 182 | /// Retrieve a timestamp offset in the database format. 183 | /// 184 | /// DateTimeOffset. 185 | /// String. 186 | public abstract string GenerateTimestampOffset(DateTimeOffset ts); 187 | 188 | #endregion 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/DatabaseQueryEvent.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.Text; 7 | 8 | /// 9 | /// Database query event arguments. 10 | /// 11 | public class DatabaseQueryEvent : EventArgs 12 | { 13 | #region Public-Members 14 | 15 | /// 16 | /// Query. 17 | /// 18 | public string Query { get; private set; } = null; 19 | 20 | /// 21 | /// Total runtime in milliseconds. 22 | /// 23 | public double TotalMilliseconds { get; private set; } = 0; 24 | 25 | /// 26 | /// Result. 27 | /// 28 | public DataTable Result { get; private set; } = null; 29 | 30 | /// 31 | /// Number of rows returned. 32 | /// 33 | public int RowsReturned 34 | { 35 | get 36 | { 37 | if (Result != null 38 | && Result.Rows != null) 39 | { 40 | return Result.Rows.Count; 41 | } 42 | 43 | return 0; 44 | } 45 | } 46 | 47 | /// 48 | /// Exception, if any. 49 | /// 50 | public Exception Exception { get; private set; } = null; 51 | 52 | #endregion 53 | 54 | #region Private-Members 55 | 56 | #endregion 57 | 58 | #region Constructors-and-Factories 59 | 60 | /// 61 | /// Instantiate. 62 | /// 63 | /// Query. 64 | /// Total runtime in milliseconds. 65 | /// Result. 66 | /// Exception, if any. 67 | public DatabaseQueryEvent(string query, double totalMs, DataTable result, Exception ex = null) 68 | { 69 | if (String.IsNullOrEmpty(query)) throw new ArgumentNullException(nameof(query)); 70 | if (totalMs < 0) throw new ArgumentOutOfRangeException(nameof(totalMs)); 71 | Query = query; 72 | TotalMilliseconds = totalMs; 73 | Result = result; 74 | Exception = ex; 75 | } 76 | 77 | #endregion 78 | 79 | #region Public-Methods 80 | 81 | #endregion 82 | 83 | #region Private-Methods 84 | 85 | #endregion 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/DatabaseSettings.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | /// 8 | /// Database settings. 9 | /// 10 | public class DatabaseSettings 11 | { 12 | #region Public-Members 13 | 14 | /// 15 | /// Filename, if using Sqlite. 16 | /// 17 | public string Filename { get; set; } = null; 18 | 19 | /// 20 | /// The type of database. 21 | /// 22 | public DbTypeEnum Type { get; set; } = DbTypeEnum.Sqlite; 23 | 24 | /// 25 | /// The hostname of the database server. 26 | /// 27 | public string Hostname { get; set; } = null; 28 | 29 | /// 30 | /// The TCP port number on which the server is listening. 31 | /// 32 | public int Port 33 | { 34 | get 35 | { 36 | return _Port; 37 | } 38 | set 39 | { 40 | if (value < 0) throw new ArgumentOutOfRangeException(nameof(Port)); 41 | _Port = value; 42 | } 43 | } 44 | 45 | /// 46 | /// The username to use when accessing the database. 47 | /// 48 | public string Username { get; set; } = null; 49 | 50 | /// 51 | /// The password to use when accessing the database. 52 | /// 53 | public string Password { get; set; } = null; 54 | 55 | /// 56 | /// For SQL Server Express, the instance name. 57 | /// 58 | public string Instance { get; set; } = null; 59 | 60 | /// 61 | /// The name of the database. 62 | /// 63 | public string DatabaseName { get; set; } = null; 64 | 65 | /// 66 | /// Boolean indicating if encryption should be required. 67 | /// 68 | public bool RequireEncryption { get; set; } = false; 69 | 70 | /// 71 | /// Debug settings. 72 | /// 73 | public DebugSettings Debug 74 | { 75 | get 76 | { 77 | return _Debug; 78 | } 79 | set 80 | { 81 | if (value == null) throw new ArgumentNullException(nameof(Debug)); 82 | _Debug = value; 83 | } 84 | } 85 | 86 | #endregion 87 | 88 | #region Private-Members 89 | 90 | private int _Port = 0; 91 | private DebugSettings _Debug = new DebugSettings(); 92 | 93 | #endregion 94 | 95 | #region Constructors-and-Factories 96 | 97 | /// 98 | /// Instantiate the object. 99 | /// 100 | public DatabaseSettings() 101 | { 102 | 103 | } 104 | 105 | /// 106 | /// Instantiate the object using Sqlite. 107 | /// 108 | /// The Sqlite database filename. 109 | public DatabaseSettings(string filename) 110 | { 111 | if (String.IsNullOrEmpty(filename)) throw new ArgumentNullException(nameof(filename)); 112 | Type = DbTypeEnum.Sqlite; 113 | Filename = filename; 114 | } 115 | 116 | /// 117 | /// Instantiate the object using SQL Server, MySQL, or PostgreSQL. 118 | /// 119 | /// The type of database. 120 | /// The hostname of the database server. 121 | /// The TCP port number on which the server is listening. 122 | /// The username to use when accessing the database. 123 | /// The password to use when accessing the database. 124 | /// The name of the database. 125 | public DatabaseSettings(string dbType, string hostname, int port, string username, string password, string dbName) 126 | { 127 | if (String.IsNullOrEmpty(dbType)) throw new ArgumentNullException(nameof(dbType)); 128 | if (String.IsNullOrEmpty(hostname)) throw new ArgumentNullException(nameof(hostname)); 129 | if (String.IsNullOrEmpty(dbName)) throw new ArgumentNullException(nameof(dbName)); 130 | 131 | Type = (DbTypeEnum)(Enum.Parse(typeof(DbTypeEnum), dbType)); 132 | if (Type == DbTypeEnum.Sqlite) throw new ArgumentException("For Sqlite, use the filename constructor."); 133 | 134 | Hostname = hostname; 135 | Port = port; 136 | Username = username; 137 | Password = password; 138 | Instance = null; 139 | DatabaseName = dbName; 140 | } 141 | 142 | /// 143 | /// Instantiate the object using SQL Server, MySQL, or PostgreSQL. 144 | /// 145 | /// The type of database. 146 | /// The hostname of the database server. 147 | /// The TCP port number on which the server is listening. 148 | /// The username to use when accessing the database. 149 | /// The password to use when accessing the database. 150 | /// The name of the database. 151 | public DatabaseSettings(DbTypeEnum dbType, string hostname, int port, string username, string password, string dbName) 152 | { 153 | if (String.IsNullOrEmpty(hostname)) throw new ArgumentNullException(nameof(hostname)); 154 | if (String.IsNullOrEmpty(dbName)) throw new ArgumentNullException(nameof(dbName)); 155 | 156 | Type = dbType; 157 | if (Type == DbTypeEnum.Sqlite) throw new ArgumentException("For Sqlite, use the filename constructor for DatabaseSettings."); 158 | 159 | Hostname = hostname; 160 | Port = port; 161 | Username = username; 162 | Password = password; 163 | Instance = null; 164 | DatabaseName = dbName; 165 | } 166 | 167 | /// 168 | /// Instantiate the object for SQL Server Express. 169 | /// 170 | /// The hostname of the database server. 171 | /// The TCP port number on which the server is listening. 172 | /// The username to use when accessing the database. 173 | /// The password to use when accessing the database. 174 | /// For SQL Server Express, the instance name. 175 | /// The name of the database. 176 | public DatabaseSettings(string hostname, int port, string username, string password, string instance, string dbName) 177 | { 178 | if (String.IsNullOrEmpty(hostname)) throw new ArgumentNullException(nameof(hostname)); 179 | if (String.IsNullOrEmpty(dbName)) throw new ArgumentNullException(nameof(dbName)); 180 | 181 | Type = DbTypeEnum.SqlServer; 182 | Hostname = hostname; 183 | Port = port; 184 | Username = username; 185 | Password = password; 186 | Instance = instance; 187 | DatabaseName = dbName; 188 | } 189 | 190 | #endregion 191 | 192 | #region Public-Methods 193 | 194 | #endregion 195 | 196 | #region Private-Methods 197 | 198 | #endregion 199 | 200 | #region Public-Embedded-Classes 201 | 202 | /// 203 | /// Debug settings. 204 | /// 205 | public class DebugSettings 206 | { 207 | /// 208 | /// Enable debugging for queries. 209 | /// 210 | public bool EnableForQueries { get; set; } = false; 211 | 212 | /// 213 | /// Enable debugging for results. 214 | /// 215 | public bool EnableForResults { get; set; } = false; 216 | 217 | /// 218 | /// Action to invoke when sending a debug message. 219 | /// 220 | public Action Logger { get; set; } = null; 221 | 222 | /// 223 | /// Instantiate. 224 | /// 225 | public DebugSettings() 226 | { 227 | 228 | } 229 | } 230 | 231 | #endregion 232 | } 233 | } -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/DatabaseWrapper.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | Joel Christner 9 | Do not install this package directly. Core classes for DatabaseWrapper packages. 10 | (c)2025 Joel Christner 11 | LICENSE.md 12 | https://github.com/jchristn/DatabaseWrapper 13 | 14 | https://github.com/jchristn/DatabaseWrapper 15 | Github 16 | true 17 | DatabaseWrapper.Core.xml 18 | true 19 | icon.png 20 | true 21 | README.md 22 | True 23 | snupkg 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Always 35 | 36 | 37 | Always 38 | 39 | 40 | Always 41 | 42 | 43 | Always 44 | 45 | 46 | True 47 | \ 48 | 49 | 50 | True 51 | 52 | 53 | 54 | True 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/DbTypeEnum.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Runtime.Serialization; 9 | 10 | /// 11 | /// Enumeration containing the supported database types. 12 | /// 13 | public enum DbTypeEnum 14 | { 15 | /// 16 | /// Microsoft SQL Server 17 | /// 18 | [EnumMember(Value = "SqlServer")] 19 | SqlServer, 20 | /// 21 | /// MySQL 22 | /// 23 | [EnumMember(Value = "Mysql")] 24 | Mysql, 25 | /// 26 | /// PostgreSQL 27 | /// 28 | [EnumMember(Value = "Postgresql")] 29 | Postgresql, 30 | /// 31 | /// Sqlite 32 | /// 33 | [EnumMember(Value = "Sqlite")] 34 | Sqlite, 35 | /// 36 | /// Oracle 37 | /// 38 | [EnumMember(Value = "Oracle")] 39 | Oracle 40 | } 41 | } -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/Helper.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.Dynamic; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | /// 14 | /// Static helper methods for DatabaseWrapper. 15 | /// 16 | public class Helper 17 | { 18 | /// 19 | /// Determines if an object is of a List type. 20 | /// 21 | /// Object. 22 | /// True if the object is of a List type. 23 | public static bool IsList(object o) 24 | { 25 | if (o == null) return false; 26 | return o is IList && 27 | o.GetType().IsGenericType && 28 | o.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>)); 29 | } 30 | 31 | /// 32 | /// Convert an object to a List object. 33 | /// 34 | /// Object. 35 | /// List object. 36 | public static List ObjectToList(object obj) 37 | { 38 | if (obj == null) return null; 39 | List ret = new List(); 40 | var enumerator = ((IEnumerable)obj).GetEnumerator(); 41 | while (enumerator.MoveNext()) 42 | { 43 | ret.Add(enumerator.Current); 44 | } 45 | return ret; 46 | } 47 | 48 | /// 49 | /// Determine if a DataTable is null or has no rows. 50 | /// 51 | /// DataTable. 52 | /// True if DataTable is null or has no rows. 53 | public static bool DataTableIsNullOrEmpty(DataTable table) 54 | { 55 | if (table == null) return true; 56 | if (table.Rows.Count < 1) return true; 57 | return false; 58 | } 59 | 60 | /// 61 | /// Convert a DataTable to an object. 62 | /// 63 | /// Type of object. 64 | /// DataTable. 65 | /// Object of specified type. 66 | public static T DataTableToObject(DataTable table) where T : new() 67 | { 68 | if (table == null) throw new ArgumentNullException(nameof(table)); 69 | if (table.Rows.Count < 1) throw new ArgumentException("No rows in DataTable"); 70 | foreach (DataRow r in table.Rows) 71 | { 72 | return DataRowToObject(r); 73 | } 74 | return default(T); 75 | } 76 | 77 | /// 78 | /// Convert a DataRow to an object. 79 | /// 80 | /// Type of object. 81 | /// DataRow. 82 | /// Object of specified type. 83 | public static T DataRowToObject(DataRow row) where T : new() 84 | { 85 | if (row == null) throw new ArgumentNullException(nameof(row)); 86 | T item = new T(); 87 | IList properties = typeof(T).GetProperties().ToList(); 88 | foreach (var property in properties) 89 | { 90 | property.SetValue(item, row[property.Name], null); 91 | } 92 | return item; 93 | } 94 | 95 | /// 96 | /// Convert a DataTable to a List of dynamic objects. 97 | /// 98 | /// DataTable. 99 | /// List of dynamic objects. 100 | public static List DataTableToListDynamic(DataTable table) 101 | { 102 | List ret = new List(); 103 | if (table == null || table.Rows.Count < 1) return ret; 104 | 105 | foreach (DataRow curr in table.Rows) 106 | { 107 | dynamic dyn = new ExpandoObject(); 108 | foreach (DataColumn col in table.Columns) 109 | { 110 | var dic = (IDictionary)dyn; 111 | dic[col.ColumnName] = curr[col]; 112 | } 113 | ret.Add(dyn); 114 | } 115 | 116 | return ret; 117 | } 118 | 119 | /// 120 | /// Convert a DataTable to a dynamic object. 121 | /// 122 | /// DataTable. 123 | /// Dynamic object. 124 | public static dynamic DataTableToDynamic(DataTable table) 125 | { 126 | dynamic ret = new ExpandoObject(); 127 | if (table == null || table.Rows.Count < 1) return ret; 128 | if (table.Rows.Count != 1) throw new ArgumentException("DataTable must contain only one row."); 129 | 130 | foreach (DataRow curr in table.Rows) 131 | { 132 | foreach (DataColumn col in table.Columns) 133 | { 134 | var dic = (IDictionary)ret; 135 | dic[col.ColumnName] = curr[col]; 136 | } 137 | 138 | return ret; 139 | } 140 | 141 | return ret; 142 | } 143 | 144 | /// 145 | /// Convert a DataTable to a List Dictionary. 146 | /// 147 | /// DataTable. 148 | /// List Dictionary. 149 | public static List> DataTableToListDictionary(DataTable table) 150 | { 151 | List> ret = new List>(); 152 | if (table == null || table.Rows.Count < 1) return ret; 153 | 154 | foreach (DataRow curr in table.Rows) 155 | { 156 | Dictionary currDict = new Dictionary(); 157 | 158 | foreach (DataColumn col in table.Columns) 159 | { 160 | currDict.Add(col.ColumnName, curr[col]); 161 | } 162 | 163 | ret.Add(currDict); 164 | } 165 | 166 | return ret; 167 | } 168 | 169 | /// 170 | /// Convert a DataTable to a Dictionary. 171 | /// 172 | /// DataTable. 173 | /// Dictionary. 174 | public static Dictionary DataTableToDictionary(DataTable table) 175 | { 176 | Dictionary ret = new Dictionary(); 177 | if (table == null || table.Rows.Count < 1) return ret; 178 | if (table.Rows.Count != 1) throw new ArgumentException("DataTable must contain only one row."); 179 | 180 | foreach (DataRow curr in table.Rows) 181 | { 182 | foreach (DataColumn col in table.Columns) 183 | { 184 | ret.Add(col.ColumnName, curr[col]); 185 | } 186 | 187 | return ret; 188 | } 189 | 190 | return ret; 191 | } 192 | 193 | /// 194 | /// Determine if string contains extended characters. 195 | /// 196 | /// String. 197 | /// True if string contains extended characters. 198 | public static bool IsExtendedCharacters(string data) 199 | { 200 | if (String.IsNullOrEmpty(data)) return false; 201 | foreach (char c in data) 202 | { 203 | if ((int)c > 255) return true; 204 | } 205 | return false; 206 | } 207 | 208 | /// 209 | /// Retrieve the DataType from the column type. 210 | /// 211 | /// String containing column type. 212 | /// DataTypeEnum. 213 | public static DataTypeEnum DataTypeFromString(string s) 214 | { 215 | if (String.IsNullOrEmpty(s)) throw new ArgumentNullException(nameof(s)); 216 | 217 | s = s.ToLower(); 218 | if (s.Contains("(")) s = s.Substring(0, s.IndexOf("(")); 219 | 220 | switch (s) 221 | { 222 | case "bigserial": // pgsql 223 | case "bigint": // mssql 224 | return DataTypeEnum.Long; 225 | 226 | case "boolean": // pgsql 227 | case "bit": // mssql 228 | case "smallserial": // pgsql 229 | case "smallest": // pgsql 230 | case "tinyint": // mssql, mysql 231 | case "integer": // pgsql, sqlite 232 | case "int": // mssql, mysql 233 | case "smallint": // mssql, mysql 234 | case "mediumint": // mysql 235 | case "serial": // pgsql 236 | return DataTypeEnum.Int; 237 | 238 | case "real": // pgsql, sqlite 239 | case "double": // mysql 240 | case "double precision": // pgsql 241 | case "float": // mysql 242 | return DataTypeEnum.Double; 243 | 244 | case "decimal": // mssql 245 | case "numeric": // mssql 246 | return DataTypeEnum.Decimal; 247 | 248 | case "timestamp without timezone": // pgsql 249 | case "timestamp without time zone": // pgsql 250 | case "time without timezone": // pgsql 251 | case "time without time zone": // pgsql 252 | case "time": // mssql, mysql 253 | case "date": // mssql, mysql 254 | case "datetime": // mssql, mysql 255 | case "datetime2": // mssql 256 | case "timestamp": // mysql 257 | return DataTypeEnum.DateTime; 258 | 259 | case "time with timezone": // pgsql 260 | case "time with time zone": // pgsql 261 | case "timestamp with timezone": // pgsql 262 | case "timestamp with time zone": // pgsql 263 | case "datetimeoffset": // mssql 264 | return DataTypeEnum.DateTimeOffset; 265 | 266 | case "enum": // mysql 267 | case "character": // pgsql 268 | case "char": // mssql, mysql, pgsql 269 | case "text": // mssql, mysql, pgsql, sqlite 270 | case "tinytext": // mysql 271 | case "mediumtext": // mysql 272 | case "longtext": // mysql 273 | case "varchar": // mssql, mysql, pgsql 274 | return DataTypeEnum.Varchar; 275 | 276 | case "character varying": // pgsql 277 | case "nchar": 278 | case "ntext": 279 | case "nvarchar": 280 | return DataTypeEnum.Nvarchar; // mssql 281 | 282 | case "blob": // sqlite, mysql 283 | case "tinyblob": // mysql 284 | case "mediumblob": // mysql 285 | case "longblob": // mysql 286 | case "bytea": // pgsql 287 | case "varbinary": // mssql 288 | return DataTypeEnum.Blob; 289 | 290 | default: 291 | return DataTypeEnum.Unknown; 292 | } 293 | } 294 | 295 | /// 296 | /// Convert byte array to hex string. 297 | /// 298 | /// Byte array. 299 | /// Hex string. 300 | public static string ByteArrayToHexString(byte[] bytes) 301 | { 302 | if (bytes == null) return null; 303 | if (bytes.Length < 1) return ""; 304 | StringBuilder hex = new StringBuilder(bytes.Length * 2); 305 | foreach (byte b in bytes) hex.AppendFormat("{0:x2}", b); 306 | return hex.ToString(); 307 | } 308 | 309 | /// 310 | /// Convert hex string to byte array. 311 | /// 312 | /// Hex string. 313 | /// Byte array. 314 | public static byte[] HexStringToBytes(string hex) 315 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 316 | { 317 | if (String.IsNullOrEmpty(hex)) throw new ArgumentNullException(nameof(hex)); 318 | if (hex.Length % 2 == 1) throw new ArgumentException("The supplied hex cannot have an odd number of digits."); 319 | 320 | byte[] arr = new byte[hex.Length >> 1]; 321 | 322 | for (int i = 0; i < hex.Length >> 1; ++i) 323 | { 324 | arr[i] = (byte)((GetHexValue(hex[i << 1]) << 4) + (GetHexValue(hex[(i << 1) + 1]))); 325 | } 326 | 327 | return arr; 328 | } 329 | 330 | private static int GetHexValue(char hex) 331 | { 332 | int val = (int)hex; 333 | // For uppercase A-F letters: 334 | // return val - (val < 58 ? 48 : 55); 335 | // For lowercase a-f letters: 336 | // return val - (val < 58 ? 48 : 87); 337 | // Or the two combined, but a bit slower: 338 | return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/OrderDirectionEnum.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Runtime.Serialization; 9 | 10 | /// 11 | /// Direction by which results should be returned. 12 | /// 13 | public enum OrderDirectionEnum 14 | { 15 | /// 16 | /// Return results in ascending order. 17 | /// 18 | [EnumMember(Value = "Ascending")] 19 | Ascending, 20 | /// 21 | /// Return results in descending order. 22 | /// 23 | [EnumMember(Value = "Descending")] 24 | Descending 25 | } 26 | } -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/ResultOrder.cs: -------------------------------------------------------------------------------- 1 | namespace DatabaseWrapper.Core 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | /// 8 | /// Describe on which columns and in which direction results should be ordered. 9 | /// 10 | public class ResultOrder 11 | { 12 | #region Public-Members 13 | 14 | /// 15 | /// Column name on which to order results. 16 | /// 17 | public string ColumnName { get; set; } = null; 18 | 19 | /// 20 | /// Direction by which results should be returned. 21 | /// 22 | public OrderDirectionEnum Direction { get; set; } = OrderDirectionEnum.Ascending; 23 | 24 | #endregion 25 | 26 | #region Private-Members 27 | 28 | #endregion 29 | 30 | #region Constructors-and-Factories 31 | 32 | /// 33 | /// Instantiate the object. 34 | /// 35 | public ResultOrder() 36 | { 37 | } 38 | 39 | /// 40 | /// Instantiate the object. 41 | /// 42 | /// Column name on which to order results. 43 | /// Direction by which results should be returned. 44 | public ResultOrder(string columnName, OrderDirectionEnum direction) 45 | { 46 | if (String.IsNullOrEmpty(columnName)) throw new ArgumentNullException(nameof(columnName)); 47 | ColumnName = columnName; 48 | Direction = direction; 49 | } 50 | 51 | #endregion 52 | 53 | #region Public-Methods 54 | 55 | #endregion 56 | 57 | #region Private-Methods 58 | 59 | #endregion 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Core/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper.Core/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Core/assets/icon.png -------------------------------------------------------------------------------- /src/DatabaseWrapper.Mysql/DatabaseWrapper.Mysql.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | Joel Christner 9 | Joel Christner 10 | Simple database wrapper for MySQL written in C# supporting dynamic query building and nesting using expressions. Refer to other DatabaseWrapper packages for support for SQL Server, Sqlite, and PostgreSQL. 11 | (c)2025 Joel Christner 12 | LICENSE.md 13 | https://github.com/jchristn/DatabaseWrapper 14 | 15 | https://github.com/jchristn/DatabaseWrapper 16 | Github 17 | true 18 | DatabaseWrapper.Core.xml 19 | true 20 | icon.png 21 | true 22 | README.md 23 | True 24 | snupkg 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Always 34 | 35 | 36 | Always 37 | 38 | 39 | Always 40 | 41 | 42 | Always 43 | 44 | 45 | True 46 | \ 47 | 48 | 49 | True 50 | 51 | 52 | 53 | True 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Mysql/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper.Mysql/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Mysql/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper.Mysql/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Mysql/assets/icon.png -------------------------------------------------------------------------------- /src/DatabaseWrapper.Oracle/DatabaseWrapper.Oracle.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | Joel Christner 9 | Joel Christner 10 | Simple database wrapper for Oracle written in C# supporting dynamic query building and nesting using expressions. Refer to other DatabaseWrapper packages for support for SQL Server, Sqlite, and PostgreSQL. 11 | (c)2025 Joel Christner 12 | LICENSE.md 13 | https://github.com/jchristn/DatabaseWrapper 14 | 15 | https://github.com/jchristn/DatabaseWrapper 16 | Github 17 | true 18 | DatabaseWrapper.Core.xml 19 | true 20 | icon.png 21 | true 22 | README.md 23 | True 24 | snupkg 25 | 26 | 27 | 28 | 29 | Always 30 | 31 | 32 | Always 33 | 34 | 35 | Always 36 | 37 | 38 | Always 39 | 40 | 41 | True 42 | \ 43 | 44 | 45 | True 46 | 47 | 48 | 49 | True 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 23.7.0 61 | 62 | 63 | 64 | 65 | 66 | 23.7.0 67 | 68 | 69 | 70 | 71 | 72 | 23.5.0 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Oracle/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper.Oracle/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Oracle/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper.Oracle/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Oracle/assets/icon.png -------------------------------------------------------------------------------- /src/DatabaseWrapper.Postgresql/DatabaseWrapper.Postgresql.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | Joel Christner 9 | Simple database wrapper for Postgresql written in C# supporting dynamic query building and nesting using expressions. Refer to other DatabaseWrapper packages for support for SQL Server, Sqlite, and MySQL. 10 | (c)2025 Joel Christner 11 | LICENSE.md 12 | https://github.com/jchristn/DatabaseWrapper 13 | 14 | https://github.com/jchristn/DatabaseWrapper 15 | Github 16 | true 17 | DatabaseWrapper.Core.xml 18 | true 19 | icon.png 20 | true 21 | README.md 22 | True 23 | snupkg 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Always 33 | 34 | 35 | Always 36 | 37 | 38 | Always 39 | 40 | 41 | Always 42 | 43 | 44 | True 45 | \ 46 | 47 | 48 | True 49 | 50 | 51 | 52 | True 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Postgresql/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper.Postgresql/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Postgresql/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper.Postgresql/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Postgresql/assets/icon.png -------------------------------------------------------------------------------- /src/DatabaseWrapper.SqlServer/DatabaseWrapper.SqlServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | Joel Christner 9 | Joel Christner 10 | Simple database wrapper for SQL Server written in C# supporting dynamic query building and nesting using expressions. Refer to other DatabaseWrapper packages for support for MySQL, Sqlite, and PostgreSQL. 11 | (c)2025 Joel Christner 12 | LICENSE.md 13 | https://github.com/jchristn/DatabaseWrapper 14 | 15 | https://github.com/jchristn/DatabaseWrapper 16 | Github 17 | true 18 | DatabaseWrapper.Core.xml 19 | true 20 | icon.png 21 | true 22 | README.md 23 | True 24 | snupkg 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Always 35 | 36 | 37 | Always 38 | 39 | 40 | Always 41 | 42 | 43 | Always 44 | 45 | 46 | True 47 | \ 48 | 49 | 50 | True 51 | 52 | 53 | 54 | True 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.SqlServer/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper.SqlServer/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.SqlServer/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper.SqlServer/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.SqlServer/assets/icon.png -------------------------------------------------------------------------------- /src/DatabaseWrapper.Sqlite/DatabaseWrapper.Sqlite.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | Joel Christner 9 | Simple database wrapper for Sqlite written in C# supporting dynamic query building and nesting using expressions. Refer to other DatabaseWrapper packages for support for SQL Server, MySQL, and PostgreSQL. 10 | (c)2025 Joel Christner 11 | LICENSE.md 12 | https://github.com/jchristn/DatabaseWrapper 13 | 14 | https://github.com/jchristn/DatabaseWrapper 15 | Github 16 | true 17 | DatabaseWrapper.Core.xml 18 | true 19 | icon.png 20 | true 21 | README.md 22 | True 23 | snupkg 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Always 33 | 34 | 35 | Always 36 | 37 | 38 | Always 39 | 40 | 41 | Always 42 | 43 | 44 | True 45 | \ 46 | 47 | 48 | True 49 | 50 | 51 | 52 | True 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/DatabaseWrapper.Sqlite/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper.Sqlite/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Sqlite/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper.Sqlite/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper.Sqlite/assets/icon.png -------------------------------------------------------------------------------- /src/DatabaseWrapper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32328.378 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper", "DatabaseWrapper\DatabaseWrapper.csproj", "{95C16D74-8F0A-421C-8F30-5DBDADD8A364}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper.Sqlite", "DatabaseWrapper.Sqlite\DatabaseWrapper.Sqlite.csproj", "{B73B2398-210A-4CE2-9642-4F05558F3C17}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper.SqlServer", "DatabaseWrapper.SqlServer\DatabaseWrapper.SqlServer.csproj", "{7F15F798-E25D-435D-AE04-9BFF208B2246}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper.Mysql", "DatabaseWrapper.Mysql\DatabaseWrapper.Mysql.csproj", "{F1230033-03BE-451C-8786-13E56D73F665}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper.Postgresql", "DatabaseWrapper.Postgresql\DatabaseWrapper.Postgresql.csproj", "{DDCDF70A-7A8F-420E-B8FE-F56039A4BEAF}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper.Core", "DatabaseWrapper.Core\DatabaseWrapper.Core.csproj", "{F78FFF28-C3E5-4D3D-90CF-14A9A47B6958}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{0963CA1B-0DD7-4AC2-9A98-73B8A8258A06}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.DatabaseConsole", "Test.DatabaseConsole\Test.DatabaseConsole.csproj", "{E7595B6D-37F5-4B1F-B2B0-2CBF12EB872D}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Mysql", "Test.Mysql\Test.Mysql.csproj", "{D90D908B-BB94-45B2-B801-82F95C60337C}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.NuGet", "Test.NuGet\Test.NuGet.csproj", "{BD8FEA20-8C4D-4645-BB28-8C80618FCD11}" 25 | EndProject 26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Postgresql", "Test.Postgresql\Test.Postgresql.csproj", "{F3654C22-82BB-4A84-B378-265103D44900}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Sqlite", "Test.Sqlite\Test.Sqlite.csproj", "{EDB58091-8C6D-4835-9712-9B352CA22647}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.SqlServer", "Test.SqlServer\Test.SqlServer.csproj", "{DDCAC74D-C2F3-442D-940A-75FA7B81B328}" 31 | EndProject 32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Async", "Test.Async\Test.Async.csproj", "{0963CA1B-0DD7-4AC2-9A98-73B8A8258A07}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.DatabaseConsoleAsync", "Test.DatabaseConsoleAsync\Test.DatabaseConsoleAsync.csproj", "{E7595B6D-37F5-4B1F-B2B0-2CBF12EB872E}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.MysqlAsync", "Test.MysqlAsync\Test.MysqlAsync.csproj", "{D90D908B-BB94-45B2-B801-82F95C60337D}" 37 | EndProject 38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.NuGetAsync", "Test.NuGetAsync\Test.NuGetAsync.csproj", "{BD8FEA20-8C4D-4645-BB28-8C80618FCD12}" 39 | EndProject 40 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.PostgresqlAsync", "Test.PostgresqlAsync\Test.PostgresqlAsync.csproj", "{F3654C22-82BB-4A84-B378-265103D44901}" 41 | EndProject 42 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.SqliteAsync", "Test.SqliteAsync\Test.SqliteAsync.csproj", "{EDB58091-8C6D-4835-9712-9B352CA22648}" 43 | EndProject 44 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.SqlServerAsync", "Test.SqlServerAsync\Test.SqlServerAsync.csproj", "{DDCAC74D-C2F3-442D-940A-75FA7B81B329}" 45 | EndProject 46 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseWrapper.Oracle", "DatabaseWrapper.Oracle\DatabaseWrapper.Oracle.csproj", "{510D84C0-F8F9-4D01-A82F-81F9EB7F961C}" 47 | EndProject 48 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Oracle", "Test.Oracle\Test.Oracle.csproj", "{1DA521CE-105D-4E38-BCEE-B8BE2886583C}" 49 | EndProject 50 | Global 51 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 52 | Debug|Any CPU = Debug|Any CPU 53 | Release|Any CPU = Release|Any CPU 54 | EndGlobalSection 55 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 56 | {95C16D74-8F0A-421C-8F30-5DBDADD8A364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {95C16D74-8F0A-421C-8F30-5DBDADD8A364}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {95C16D74-8F0A-421C-8F30-5DBDADD8A364}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {95C16D74-8F0A-421C-8F30-5DBDADD8A364}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {B73B2398-210A-4CE2-9642-4F05558F3C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {B73B2398-210A-4CE2-9642-4F05558F3C17}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {B73B2398-210A-4CE2-9642-4F05558F3C17}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {B73B2398-210A-4CE2-9642-4F05558F3C17}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {7F15F798-E25D-435D-AE04-9BFF208B2246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {7F15F798-E25D-435D-AE04-9BFF208B2246}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {7F15F798-E25D-435D-AE04-9BFF208B2246}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {7F15F798-E25D-435D-AE04-9BFF208B2246}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {F1230033-03BE-451C-8786-13E56D73F665}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {F1230033-03BE-451C-8786-13E56D73F665}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {F1230033-03BE-451C-8786-13E56D73F665}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {F1230033-03BE-451C-8786-13E56D73F665}.Release|Any CPU.Build.0 = Release|Any CPU 72 | {DDCDF70A-7A8F-420E-B8FE-F56039A4BEAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {DDCDF70A-7A8F-420E-B8FE-F56039A4BEAF}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {DDCDF70A-7A8F-420E-B8FE-F56039A4BEAF}.Release|Any CPU.ActiveCfg = Release|Any CPU 75 | {DDCDF70A-7A8F-420E-B8FE-F56039A4BEAF}.Release|Any CPU.Build.0 = Release|Any CPU 76 | {F78FFF28-C3E5-4D3D-90CF-14A9A47B6958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 77 | {F78FFF28-C3E5-4D3D-90CF-14A9A47B6958}.Debug|Any CPU.Build.0 = Debug|Any CPU 78 | {F78FFF28-C3E5-4D3D-90CF-14A9A47B6958}.Release|Any CPU.ActiveCfg = Release|Any CPU 79 | {F78FFF28-C3E5-4D3D-90CF-14A9A47B6958}.Release|Any CPU.Build.0 = Release|Any CPU 80 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 81 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A06}.Debug|Any CPU.Build.0 = Debug|Any CPU 82 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A06}.Release|Any CPU.ActiveCfg = Release|Any CPU 83 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A06}.Release|Any CPU.Build.0 = Release|Any CPU 84 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 85 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872D}.Debug|Any CPU.Build.0 = Debug|Any CPU 86 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872D}.Release|Any CPU.ActiveCfg = Release|Any CPU 87 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872D}.Release|Any CPU.Build.0 = Release|Any CPU 88 | {D90D908B-BB94-45B2-B801-82F95C60337C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 89 | {D90D908B-BB94-45B2-B801-82F95C60337C}.Debug|Any CPU.Build.0 = Debug|Any CPU 90 | {D90D908B-BB94-45B2-B801-82F95C60337C}.Release|Any CPU.ActiveCfg = Release|Any CPU 91 | {D90D908B-BB94-45B2-B801-82F95C60337C}.Release|Any CPU.Build.0 = Release|Any CPU 92 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 93 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD11}.Debug|Any CPU.Build.0 = Debug|Any CPU 94 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD11}.Release|Any CPU.ActiveCfg = Release|Any CPU 95 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD11}.Release|Any CPU.Build.0 = Release|Any CPU 96 | {F3654C22-82BB-4A84-B378-265103D44900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 97 | {F3654C22-82BB-4A84-B378-265103D44900}.Debug|Any CPU.Build.0 = Debug|Any CPU 98 | {F3654C22-82BB-4A84-B378-265103D44900}.Release|Any CPU.ActiveCfg = Release|Any CPU 99 | {F3654C22-82BB-4A84-B378-265103D44900}.Release|Any CPU.Build.0 = Release|Any CPU 100 | {EDB58091-8C6D-4835-9712-9B352CA22647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 101 | {EDB58091-8C6D-4835-9712-9B352CA22647}.Debug|Any CPU.Build.0 = Debug|Any CPU 102 | {EDB58091-8C6D-4835-9712-9B352CA22647}.Release|Any CPU.ActiveCfg = Release|Any CPU 103 | {EDB58091-8C6D-4835-9712-9B352CA22647}.Release|Any CPU.Build.0 = Release|Any CPU 104 | {DDCAC74D-C2F3-442D-940A-75FA7B81B328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 105 | {DDCAC74D-C2F3-442D-940A-75FA7B81B328}.Debug|Any CPU.Build.0 = Debug|Any CPU 106 | {DDCAC74D-C2F3-442D-940A-75FA7B81B328}.Release|Any CPU.ActiveCfg = Release|Any CPU 107 | {DDCAC74D-C2F3-442D-940A-75FA7B81B328}.Release|Any CPU.Build.0 = Release|Any CPU 108 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 109 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A07}.Debug|Any CPU.Build.0 = Debug|Any CPU 110 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A07}.Release|Any CPU.ActiveCfg = Release|Any CPU 111 | {0963CA1B-0DD7-4AC2-9A98-73B8A8258A07}.Release|Any CPU.Build.0 = Release|Any CPU 112 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 113 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872E}.Debug|Any CPU.Build.0 = Debug|Any CPU 114 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872E}.Release|Any CPU.ActiveCfg = Release|Any CPU 115 | {E7595B6D-37F5-4B1F-B2B0-2CBF12EB872E}.Release|Any CPU.Build.0 = Release|Any CPU 116 | {D90D908B-BB94-45B2-B801-82F95C60337D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 117 | {D90D908B-BB94-45B2-B801-82F95C60337D}.Debug|Any CPU.Build.0 = Debug|Any CPU 118 | {D90D908B-BB94-45B2-B801-82F95C60337D}.Release|Any CPU.ActiveCfg = Release|Any CPU 119 | {D90D908B-BB94-45B2-B801-82F95C60337D}.Release|Any CPU.Build.0 = Release|Any CPU 120 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 121 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD12}.Debug|Any CPU.Build.0 = Debug|Any CPU 122 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD12}.Release|Any CPU.ActiveCfg = Release|Any CPU 123 | {BD8FEA20-8C4D-4645-BB28-8C80618FCD12}.Release|Any CPU.Build.0 = Release|Any CPU 124 | {F3654C22-82BB-4A84-B378-265103D44901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 125 | {F3654C22-82BB-4A84-B378-265103D44901}.Debug|Any CPU.Build.0 = Debug|Any CPU 126 | {F3654C22-82BB-4A84-B378-265103D44901}.Release|Any CPU.ActiveCfg = Release|Any CPU 127 | {F3654C22-82BB-4A84-B378-265103D44901}.Release|Any CPU.Build.0 = Release|Any CPU 128 | {EDB58091-8C6D-4835-9712-9B352CA22648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 129 | {EDB58091-8C6D-4835-9712-9B352CA22648}.Debug|Any CPU.Build.0 = Debug|Any CPU 130 | {EDB58091-8C6D-4835-9712-9B352CA22648}.Release|Any CPU.ActiveCfg = Release|Any CPU 131 | {EDB58091-8C6D-4835-9712-9B352CA22648}.Release|Any CPU.Build.0 = Release|Any CPU 132 | {DDCAC74D-C2F3-442D-940A-75FA7B81B329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 133 | {DDCAC74D-C2F3-442D-940A-75FA7B81B329}.Debug|Any CPU.Build.0 = Debug|Any CPU 134 | {DDCAC74D-C2F3-442D-940A-75FA7B81B329}.Release|Any CPU.ActiveCfg = Release|Any CPU 135 | {DDCAC74D-C2F3-442D-940A-75FA7B81B329}.Release|Any CPU.Build.0 = Release|Any CPU 136 | {510D84C0-F8F9-4D01-A82F-81F9EB7F961C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 137 | {510D84C0-F8F9-4D01-A82F-81F9EB7F961C}.Debug|Any CPU.Build.0 = Debug|Any CPU 138 | {510D84C0-F8F9-4D01-A82F-81F9EB7F961C}.Release|Any CPU.ActiveCfg = Release|Any CPU 139 | {510D84C0-F8F9-4D01-A82F-81F9EB7F961C}.Release|Any CPU.Build.0 = Release|Any CPU 140 | {1DA521CE-105D-4E38-BCEE-B8BE2886583C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 141 | {1DA521CE-105D-4E38-BCEE-B8BE2886583C}.Debug|Any CPU.Build.0 = Debug|Any CPU 142 | {1DA521CE-105D-4E38-BCEE-B8BE2886583C}.Release|Any CPU.ActiveCfg = Release|Any CPU 143 | {1DA521CE-105D-4E38-BCEE-B8BE2886583C}.Release|Any CPU.Build.0 = Release|Any CPU 144 | EndGlobalSection 145 | GlobalSection(SolutionProperties) = preSolution 146 | HideSolutionNode = FALSE 147 | EndGlobalSection 148 | GlobalSection(ExtensibilityGlobals) = postSolution 149 | SolutionGuid = {A6A036FC-0A83-4F0A-9212-5C19B2DE9750} 150 | EndGlobalSection 151 | EndGlobal 152 | -------------------------------------------------------------------------------- /src/DatabaseWrapper/DatabaseWrapper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net48;net6.0;net8.0 5 | 6.1.4 6 | Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates. 7 | database sql server mssql mysql pgsql sqlite postgres postgresql oracle dynamic query builder datarow datatable orm relational mapper relation key foreign 8 | true 9 | DatabaseWrapper.Core.xml 10 | true 11 | Joel Christner 12 | Joel Christner 13 | Simple database wrapper for Microsoft SQL Server, MySQL, PostgreSQL, and Sqlite. written in C# supporting dynamic query building and nesting using expressions. Refer to other DatabaseWrapper packages if you only need support for one database type. 14 | (c)2025 Joel Christner 15 | https://github.com/jchristn/DatabaseWrapper 16 | https://github.com/jchristn/DatabaseWrapper 17 | Github 18 | 19 | 20 | LICENSE.md 21 | $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage 22 | icon.png 23 | true 24 | README.md 25 | True 26 | snupkg 27 | 28 | 29 | 30 | 31 | True 32 | \ 33 | 34 | 35 | True 36 | 37 | 38 | 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Always 61 | 62 | 63 | Always 64 | 65 | 66 | Always 67 | 68 | 69 | Always 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/DatabaseWrapper/LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /src/DatabaseWrapper/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper/assets/icon.ico -------------------------------------------------------------------------------- /src/DatabaseWrapper/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/DatabaseWrapper/assets/icon.png -------------------------------------------------------------------------------- /src/Test.Async/Test.Async.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Always 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Test.Async/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.Async/headshot.png -------------------------------------------------------------------------------- /src/Test.DatabaseConsole/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Test.DatabaseConsole 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using DatabaseWrapper; 11 | using DatabaseWrapper.Core; 12 | using ExpressionTree; 13 | using GetSomeInput; 14 | using Newtonsoft.Json; 15 | using Newtonsoft.Json.Converters; 16 | 17 | class Program 18 | { 19 | static Random _Random = new Random(DateTime.Now.Millisecond); 20 | static DatabaseSettings _Settings; 21 | static DatabaseClient _Database; 22 | 23 | // To use dbo.person, change _Table to either 'dbo.person' or just '" + _Table + "' 24 | // To use with a specific schema, use 'schema.table', i.e. 'foo.person' 25 | static string _DbType = "sqlserver"; 26 | static string _User = "root"; 27 | static string _Password = "password"; 28 | static string _Hostname = "localhost"; 29 | static int _Port = 1433; 30 | static string _DbName = "test"; 31 | static bool _Debug = true; 32 | static bool _RunForever = true; 33 | 34 | static void Main(string[] args) 35 | { 36 | #region Instantiate 37 | 38 | /* 39 | * 40 | * 41 | * Create the database 'test' before proceeding if using mssql, mysql, or pgsql 42 | * 43 | * 44 | */ 45 | 46 | _DbType = Inputty.GetString("DB type [sqlserver|mysql|postgresql|sqlite]:", _DbType, false).ToLower(); 47 | 48 | if (_DbType.Equals("sqlserver") || _DbType.Equals("mysql") || _DbType.Equals("postgresql")) 49 | { 50 | Console.WriteLine("Ensure the database has been created beforehand."); 51 | Console.WriteLine(""); 52 | 53 | switch (_DbType) 54 | { 55 | case "sqlserver": 56 | _Port = 1433; 57 | break; 58 | case "mysql": 59 | _Port = 3306; 60 | break; 61 | case "postgresql": 62 | _Port = 5432; 63 | break; 64 | default: 65 | _Port = 0; 66 | break; 67 | } 68 | 69 | _User = Inputty.GetString("User:", "root", false); 70 | _Password = Inputty.GetString("Pass:", null, true); 71 | _Hostname = Inputty.GetString("Host:", _Hostname, false); 72 | _Port = Inputty.GetInteger("Port:", _Port, true, false); 73 | _DbName = Inputty.GetString("Database:", _DbName, true); 74 | 75 | switch (_DbType) 76 | { 77 | case "sqlserver": 78 | _Settings = new DatabaseSettings(_Hostname, _Port, _User, _Password, null, _DbName); 79 | _Database = new DatabaseClient(_Settings); 80 | break; 81 | case "mysql": 82 | _Settings = new DatabaseSettings(DbTypeEnum.Mysql, _Hostname, _Port, _User, _Password, _DbName); 83 | _Database = new DatabaseClient(_Settings); 84 | break; 85 | case "postgresql": 86 | _Settings = new DatabaseSettings(DbTypeEnum.Postgresql, _Hostname, _Port, _User, _Password, _DbName); 87 | _Database = new DatabaseClient(_Settings); 88 | break; 89 | default: 90 | return; 91 | } 92 | } 93 | else if (_DbType.Equals("sqlite")) 94 | { 95 | string filename = Inputty.GetString("Filename:", "sqlite.db", false); 96 | _Settings = new DatabaseSettings(filename); 97 | _Database = new DatabaseClient(_Settings); 98 | } 99 | else 100 | { 101 | Console.WriteLine("Invalid database type."); 102 | return; 103 | } 104 | 105 | _Database.QueryEvent += QueryEventHandler; 106 | 107 | #endregion 108 | 109 | #region Menu 110 | 111 | while (_RunForever) 112 | { 113 | try 114 | { 115 | string userInput = Inputty.GetString("Command [? for help]:", null, false); 116 | if (userInput.Equals("q")) 117 | { 118 | _RunForever = false; 119 | } 120 | else if (userInput.Equals("cls")) 121 | { 122 | Console.Clear(); 123 | } 124 | else if (userInput.Equals("debug")) 125 | { 126 | if (_Debug) 127 | { 128 | _Debug = false; 129 | _Settings.Debug.Logger = null; 130 | _Settings.Debug.EnableForQueries = false; 131 | _Settings.Debug.EnableForResults = false; 132 | } 133 | else 134 | { 135 | _Debug = true; 136 | _Settings.Debug.Logger = Logger; 137 | _Settings.Debug.EnableForQueries = true; 138 | _Settings.Debug.EnableForResults = true; 139 | } 140 | } 141 | else if (userInput.Equals("?")) 142 | { 143 | Console.WriteLine(""); 144 | Console.WriteLine("Available commands:"); 145 | Console.WriteLine(" q quit"); 146 | Console.WriteLine(" ? help, this menu"); 147 | Console.WriteLine(" cls clear the screen"); 148 | Console.WriteLine(" debug enable/disable debug, currently " + _Debug); 149 | Console.WriteLine(" tables show list of tables"); 150 | Console.WriteLine(" describe [table] describe a table"); 151 | Console.WriteLine(" [query] execute a query"); 152 | Console.WriteLine(""); 153 | } 154 | else if (userInput.Equals("tables")) 155 | { 156 | Dictionary> db = _Database.DescribeDatabase(); 157 | 158 | if (db != null && db.Count > 0) 159 | { 160 | Console.WriteLine(""); 161 | Console.WriteLine(db.Count + " tables"); 162 | Console.WriteLine(""); 163 | 164 | foreach (KeyValuePair> kvp in db) 165 | { 166 | Console.WriteLine("Table " + kvp.Key); 167 | foreach (Column col in kvp.Value) 168 | { 169 | Console.WriteLine( 170 | "| " + col.Name + 171 | " " + col.Type.ToString() + 172 | (col.Nullable ? " nullable" : "") + 173 | (col.PrimaryKey ? " pri" : "") + 174 | (col.Precision != null ? " precision " + col.Precision : "") + 175 | (col.MaxLength != null ? " maxlen " + col.MaxLength : "")); 176 | } 177 | } 178 | } 179 | } 180 | else if (userInput.StartsWith("describe ")) 181 | { 182 | string[] parts = userInput.Split(new[] { ' ' }, 2); 183 | if (parts != null && parts.Length == 2) 184 | { 185 | List cols = _Database.DescribeTable(parts[1]); 186 | if (cols != null && cols.Count > 0) 187 | { 188 | Console.WriteLine(""); 189 | Console.WriteLine("Table " + parts[1]); 190 | foreach (Column col in cols) 191 | { 192 | Console.WriteLine( 193 | "| " + col.Name + 194 | " " + col.Type.ToString() + 195 | (col.Nullable ? " nullable" : "") + 196 | (col.PrimaryKey ? " pri" : "") + 197 | (col.Precision != null ? " precision " + col.Precision : "") + 198 | (col.MaxLength != null ? " maxlen " + col.MaxLength : "")); 199 | } 200 | } 201 | } 202 | } 203 | else 204 | { 205 | DataTable result = _Database.Query(userInput); 206 | if (result == null || result.Rows.Count < 1) 207 | { 208 | Console.WriteLine(""); 209 | Console.WriteLine("(none)"); 210 | Console.WriteLine(""); 211 | } 212 | else 213 | { 214 | Console.WriteLine(""); 215 | dynamic data = Helper.DataTableToListDynamic(result); 216 | string json = SerializeJson(data, true); 217 | Console.WriteLine(json); 218 | Console.WriteLine(""); 219 | Console.WriteLine(result.Rows.Count + " row(s)"); 220 | Console.WriteLine(""); 221 | } 222 | } 223 | } 224 | catch (Exception e) 225 | { 226 | ExceptionConsole("Main", "Exception", e); 227 | } 228 | } 229 | 230 | #endregion 231 | } 232 | 233 | private static void QueryEventHandler(object sender, DatabaseQueryEvent e) 234 | { 235 | Console.WriteLine("---"); 236 | Console.WriteLine(" Query : " + e.Query); 237 | Console.WriteLine(" Time : " + string.Format("{0:N2}", e.TotalMilliseconds) + "ms"); 238 | Console.WriteLine(" Rows returned : " + e.RowsReturned); 239 | Console.WriteLine(" Exception : " + (e.Exception != null ? e.Exception.Message + Environment.NewLine + e.ToString() : "none")); 240 | } 241 | 242 | private static string StackToString() 243 | { 244 | string ret = ""; 245 | 246 | StackTrace t = new StackTrace(); 247 | for (int i = 0; i < t.FrameCount; i++) 248 | { 249 | if (i == 0) 250 | { 251 | ret += t.GetFrame(i).GetMethod().Name; 252 | } 253 | else 254 | { 255 | ret += " <= " + t.GetFrame(i).GetMethod().Name; 256 | } 257 | } 258 | 259 | return ret; 260 | } 261 | 262 | private static void ExceptionConsole(string method, string text, Exception e) 263 | { 264 | var st = new StackTrace(e, true); 265 | var frame = st.GetFrame(0); 266 | int line = frame.GetFileLineNumber(); 267 | string filename = frame.GetFileName(); 268 | 269 | Console.WriteLine("---"); 270 | Console.WriteLine("An exception was encountered which triggered this message."); 271 | Console.WriteLine(" Method: " + method); 272 | Console.WriteLine(" Text: " + text); 273 | Console.WriteLine(" Type: " + e.GetType().ToString()); 274 | Console.WriteLine(" Data: " + e.Data); 275 | Console.WriteLine(" Inner: " + e.InnerException); 276 | Console.WriteLine(" Message: " + e.Message); 277 | Console.WriteLine(" Source: " + e.Source); 278 | Console.WriteLine(" StackTrace: " + e.StackTrace); 279 | Console.WriteLine(" Stack: " + StackToString()); 280 | Console.WriteLine(" Line: " + line); 281 | Console.WriteLine(" File: " + filename); 282 | Console.WriteLine(" ToString: " + e.ToString()); 283 | Console.WriteLine("---"); 284 | 285 | return; 286 | } 287 | 288 | private static void Logger(string msg) 289 | { 290 | Console.WriteLine(msg); 291 | } 292 | 293 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 294 | public static string SerializeJson(object obj, bool pretty) 295 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 296 | { 297 | if (obj == null) return null; 298 | string json; 299 | 300 | if (pretty) 301 | { 302 | json = JsonConvert.SerializeObject( 303 | obj, 304 | Newtonsoft.Json.Formatting.Indented, 305 | new JsonSerializerSettings 306 | { 307 | NullValueHandling = NullValueHandling.Ignore, 308 | DateTimeZoneHandling = DateTimeZoneHandling.Utc, 309 | Converters = new List { new StringEnumConverter() } 310 | }); 311 | } 312 | else 313 | { 314 | json = JsonConvert.SerializeObject(obj, 315 | new JsonSerializerSettings 316 | { 317 | NullValueHandling = NullValueHandling.Ignore, 318 | DateTimeZoneHandling = DateTimeZoneHandling.Utc, 319 | Converters = new List { new StringEnumConverter() } 320 | }); 321 | } 322 | 323 | return json; 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /src/Test.DatabaseConsole/Test.DatabaseConsole.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Test.DatabaseConsoleAsync/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Test.DatabaseConsole 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using DatabaseWrapper; 11 | using DatabaseWrapper.Core; 12 | using ExpressionTree; 13 | using GetSomeInput; 14 | using Newtonsoft.Json; 15 | using Newtonsoft.Json.Converters; 16 | using Newtonsoft.Json.Linq; 17 | 18 | class Program 19 | { 20 | static Random _Random = new Random(DateTime.Now.Millisecond); 21 | static DatabaseSettings _Settings; 22 | static DatabaseClient _Database; 23 | 24 | // To use dbo.person, change _Table to either 'dbo.person' or just '" + _Table + "' 25 | // To use with a specific schema, use 'schema.table', i.e. 'foo.person' 26 | static string _DbType = "sqlserver"; 27 | static string _User = "root"; 28 | static string _Password = "password"; 29 | static string _Hostname = "localhost"; 30 | static int _Port = 1433; 31 | static string _DbName = "test"; 32 | static bool _Debug = true; 33 | static bool _RunForever = true; 34 | 35 | static async Task Main(string[] args) 36 | { 37 | #region Instantiate 38 | 39 | /* 40 | * 41 | * 42 | * Create the database 'test' before proceeding if using mssql, mysql, or pgsql 43 | * 44 | * 45 | */ 46 | 47 | _DbType = Inputty.GetString("DB type [sqlserver|mysql|postgresql|sqlite]:", _DbType, false).ToLower(); 48 | 49 | if (_DbType.Equals("sqlserver") || _DbType.Equals("mysql") || _DbType.Equals("postgresql")) 50 | { 51 | Console.WriteLine("Ensure the database has been created beforehand."); 52 | Console.WriteLine(""); 53 | 54 | switch (_DbType) 55 | { 56 | case "sqlserver": 57 | _Port = 1433; 58 | break; 59 | case "mysql": 60 | _Port = 3306; 61 | break; 62 | case "postgresql": 63 | _Port = 5432; 64 | break; 65 | default: 66 | _Port = 0; 67 | break; 68 | } 69 | 70 | _User = Inputty.GetString("User:", "root", false); 71 | _Password = Inputty.GetString("Pass:", null, true); 72 | _Hostname = Inputty.GetString("Host:", _Hostname, false); 73 | _Port = Inputty.GetInteger("Port:", _Port, true, false); 74 | _DbName = Inputty.GetString("Database:", _DbName, true); 75 | 76 | switch (_DbType) 77 | { 78 | case "sqlserver": 79 | _Settings = new DatabaseSettings(_Hostname, _Port, _User, _Password, null, _DbName); 80 | _Database = new DatabaseClient(_Settings); 81 | break; 82 | case "mysql": 83 | _Settings = new DatabaseSettings(DbTypeEnum.Mysql, _Hostname, _Port, _User, _Password, _DbName); 84 | _Database = new DatabaseClient(_Settings); 85 | break; 86 | case "postgresql": 87 | _Settings = new DatabaseSettings(DbTypeEnum.Postgresql, _Hostname, _Port, _User, _Password, _DbName); 88 | _Database = new DatabaseClient(_Settings); 89 | break; 90 | default: 91 | return; 92 | } 93 | } 94 | else if (_DbType.Equals("sqlite")) 95 | { 96 | string filename = Inputty.GetString("Filename:", "sqlite.db", false); 97 | _Settings = new DatabaseSettings(filename); 98 | _Database = new DatabaseClient(_Settings); 99 | } 100 | else 101 | { 102 | Console.WriteLine("Invalid database type."); 103 | return; 104 | } 105 | 106 | _Database.QueryEvent += QueryEventHandler; 107 | 108 | #endregion 109 | 110 | #region Menu 111 | 112 | while (_RunForever) 113 | { 114 | try 115 | { 116 | string userInput = Inputty.GetString("Command [? for help]:", null, false); 117 | if (userInput.Equals("q")) 118 | { 119 | _RunForever = false; 120 | } 121 | else if (userInput.Equals("cls")) 122 | { 123 | Console.Clear(); 124 | } 125 | else if (userInput.Equals("debug")) 126 | { 127 | if (_Debug) 128 | { 129 | _Debug = false; 130 | _Settings.Debug.Logger = null; 131 | _Settings.Debug.EnableForQueries = false; 132 | _Settings.Debug.EnableForResults = false; 133 | } 134 | else 135 | { 136 | _Debug = true; 137 | _Settings.Debug.Logger = Logger; 138 | _Settings.Debug.EnableForQueries = true; 139 | _Settings.Debug.EnableForResults = true; 140 | } 141 | } 142 | else if (userInput.Equals("?")) 143 | { 144 | Console.WriteLine(""); 145 | Console.WriteLine("Available commands:"); 146 | Console.WriteLine(" q quit"); 147 | Console.WriteLine(" ? help, this menu"); 148 | Console.WriteLine(" cls clear the screen"); 149 | Console.WriteLine(" debug enable/disable debug, currently " + _Debug); 150 | Console.WriteLine(" tables show list of tables"); 151 | Console.WriteLine(" describe [table] describe a table"); 152 | Console.WriteLine(" [query] execute a query"); 153 | Console.WriteLine(""); 154 | } 155 | else if (userInput.Equals("tables")) 156 | { 157 | Dictionary> db = await _Database.DescribeDatabaseAsync(); 158 | 159 | if (db != null && db.Count > 0) 160 | { 161 | Console.WriteLine(""); 162 | Console.WriteLine(db.Count + " tables"); 163 | Console.WriteLine(""); 164 | 165 | foreach (KeyValuePair> kvp in db) 166 | { 167 | Console.WriteLine("Table " + kvp.Key); 168 | foreach (Column col in kvp.Value) 169 | { 170 | Console.WriteLine( 171 | "| " + col.Name + 172 | " " + col.Type.ToString() + 173 | (col.Nullable ? " nullable" : "") + 174 | (col.PrimaryKey ? " pri" : "") + 175 | (col.Precision != null ? " precision " + col.Precision : "") + 176 | (col.MaxLength != null ? " maxlen " + col.MaxLength : "")); 177 | } 178 | } 179 | } 180 | else 181 | { 182 | Console.WriteLine(""); 183 | Console.WriteLine("No tables."); 184 | Console.WriteLine(""); 185 | } 186 | } 187 | else if (userInput.StartsWith("describe ")) 188 | { 189 | string[] parts = userInput.Split(new[] { ' ' }, 2); 190 | if (parts != null && parts.Length == 2) 191 | { 192 | List cols = await _Database.DescribeTableAsync(parts[1]); 193 | if (cols != null && cols.Count > 0) 194 | { 195 | Console.WriteLine(""); 196 | Console.WriteLine("Table " + parts[1]); 197 | foreach (Column col in cols) 198 | { 199 | Console.WriteLine( 200 | "| " + col.Name + 201 | " " + col.Type.ToString() + 202 | (col.Nullable ? " nullable" : "") + 203 | (col.PrimaryKey ? " pri" : "") + 204 | (col.Precision != null ? " precision " + col.Precision : "") + 205 | (col.MaxLength != null ? " maxlen " + col.MaxLength : "")); 206 | } 207 | } 208 | } 209 | } 210 | else 211 | { 212 | DataTable result = await _Database.QueryAsync(userInput); 213 | if (result == null || result.Rows.Count < 1) 214 | { 215 | Console.WriteLine(""); 216 | Console.WriteLine("(none)"); 217 | Console.WriteLine(""); 218 | } 219 | else 220 | { 221 | Console.WriteLine(""); 222 | dynamic data = Helper.DataTableToListDynamic(result); 223 | string json = SerializeJson(data, true); 224 | Console.WriteLine(json); 225 | Console.WriteLine(""); 226 | Console.WriteLine(result.Rows.Count + " row(s)"); 227 | Console.WriteLine(""); 228 | } 229 | } 230 | } 231 | catch (Exception e) 232 | { 233 | ExceptionConsole("Main", "Exception", e); 234 | } 235 | } 236 | 237 | #endregion 238 | } 239 | 240 | private static void QueryEventHandler(object sender, DatabaseQueryEvent e) 241 | { 242 | Console.WriteLine("---"); 243 | Console.WriteLine(" Query : " + e.Query); 244 | Console.WriteLine(" Time : " + string.Format("{0:N2}", e.TotalMilliseconds) + "ms"); 245 | Console.WriteLine(" Rows returned : " + e.RowsReturned); 246 | Console.WriteLine(" Exception : " + (e.Exception != null ? e.Exception.Message + Environment.NewLine + e.ToString() : "none")); 247 | } 248 | 249 | private static string StackToString() 250 | { 251 | string ret = ""; 252 | 253 | StackTrace t = new StackTrace(); 254 | for (int i = 0; i < t.FrameCount; i++) 255 | { 256 | if (i == 0) 257 | { 258 | ret += t.GetFrame(i).GetMethod().Name; 259 | } 260 | else 261 | { 262 | ret += " <= " + t.GetFrame(i).GetMethod().Name; 263 | } 264 | } 265 | 266 | return ret; 267 | } 268 | 269 | private static void ExceptionConsole(string method, string text, Exception e) 270 | { 271 | var st = new StackTrace(e, true); 272 | var frame = st.GetFrame(0); 273 | int line = frame.GetFileLineNumber(); 274 | string filename = frame.GetFileName(); 275 | 276 | Console.WriteLine("---"); 277 | Console.WriteLine("An exception was encountered which triggered this message."); 278 | Console.WriteLine(" Method: " + method); 279 | Console.WriteLine(" Text: " + text); 280 | Console.WriteLine(" Type: " + e.GetType().ToString()); 281 | Console.WriteLine(" Data: " + e.Data); 282 | Console.WriteLine(" Inner: " + e.InnerException); 283 | Console.WriteLine(" Message: " + e.Message); 284 | Console.WriteLine(" Source: " + e.Source); 285 | Console.WriteLine(" StackTrace: " + e.StackTrace); 286 | Console.WriteLine(" Stack: " + StackToString()); 287 | Console.WriteLine(" Line: " + line); 288 | Console.WriteLine(" File: " + filename); 289 | Console.WriteLine(" ToString: " + e.ToString()); 290 | Console.WriteLine("---"); 291 | 292 | return; 293 | } 294 | 295 | private static void Logger(string msg) 296 | { 297 | Console.WriteLine(msg); 298 | } 299 | 300 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 301 | public static string SerializeJson(object obj, bool pretty) 302 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 303 | { 304 | if (obj == null) return null; 305 | string json; 306 | 307 | if (pretty) 308 | { 309 | json = JsonConvert.SerializeObject( 310 | obj, 311 | Newtonsoft.Json.Formatting.Indented, 312 | new JsonSerializerSettings 313 | { 314 | NullValueHandling = NullValueHandling.Ignore, 315 | DateTimeZoneHandling = DateTimeZoneHandling.Utc, 316 | Converters = new List { new StringEnumConverter() } 317 | }); 318 | } 319 | else 320 | { 321 | json = JsonConvert.SerializeObject(obj, 322 | new JsonSerializerSettings 323 | { 324 | NullValueHandling = NullValueHandling.Ignore, 325 | DateTimeZoneHandling = DateTimeZoneHandling.Utc, 326 | Converters = new List { new StringEnumConverter() } 327 | }); 328 | } 329 | 330 | return json; 331 | } 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /src/Test.DatabaseConsoleAsync/Test.DatabaseConsoleAsync.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Test.Mysql/Test.Mysql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.Mysql/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.Mysql/headshot.png -------------------------------------------------------------------------------- /src/Test.MysqlAsync/Test.MysqlAsync.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.MysqlAsync/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.MysqlAsync/headshot.png -------------------------------------------------------------------------------- /src/Test.NuGet/Test.NuGet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.NuGet/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.NuGet/headshot.png -------------------------------------------------------------------------------- /src/Test.NuGetAsync/Test.NuGetAsync.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.NuGetAsync/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.NuGetAsync/headshot.png -------------------------------------------------------------------------------- /src/Test.Oracle/Test.Oracle.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.Oracle/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.Oracle/headshot.png -------------------------------------------------------------------------------- /src/Test.Postgresql/Test.Postgresql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.Postgresql/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.Postgresql/headshot.png -------------------------------------------------------------------------------- /src/Test.PostgresqlAsync/Test.PostgresqlAsync.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.PostgresqlAsync/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.PostgresqlAsync/headshot.png -------------------------------------------------------------------------------- /src/Test.SqlServer/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Test 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using DatabaseWrapper.SqlServer; 12 | using DatabaseWrapper.Core; 13 | using ExpressionTree; 14 | 15 | class Program 16 | { 17 | static Random _Random = new Random(DateTime.Now.Millisecond); 18 | static DatabaseSettings _Settings; 19 | static DatabaseClient _Database; 20 | static byte[] _FileBytes = File.ReadAllBytes("./headshot.png"); 21 | 22 | static string _Host = "localhost"; 23 | static int _Port = 1433; 24 | static string _Instance = null; // set to SQLEXPRESS for typical SQL Server Express installations 25 | 26 | // To use dbo.person, change _Table to either 'dbo.person' or just 'person' 27 | // To use with a specific schema, use 'schema.table', i.e. 'foo.person' 28 | static string _Table = "dbo.person"; 29 | 30 | static void Main(string[] args) 31 | { 32 | try 33 | { 34 | #region Select-Database-Type 35 | 36 | /* 37 | * 38 | * 39 | * Create the database 'test' before proceeding if using mssql, mysql, or pgsql 40 | * 41 | * 42 | */ 43 | 44 | Console.Write("User: "); 45 | string user = Console.ReadLine(); 46 | 47 | Console.Write("Password: "); 48 | string pass = Console.ReadLine(); 49 | 50 | _Settings = new DatabaseSettings(_Host, _Port, user, pass, _Instance, "test"); 51 | _Settings.Debug.Logger = Logger; 52 | _Settings.Debug.EnableForQueries = true; 53 | _Settings.Debug.EnableForResults = true; 54 | 55 | _Database = new DatabaseClient(_Settings); 56 | 57 | #endregion 58 | 59 | #region Sanitize-Data 60 | 61 | string[] attacks = { 62 | "' OR '1'='1", 63 | "'; DROP TABLE Users; --", 64 | "' UNION SELECT username, password FROM Users--", 65 | "' OR 1=1--", 66 | "admin' --", 67 | "'; EXEC xp_cmdshell 'net user';--", 68 | "' OR 'x'='x", 69 | "1 OR 1=1", 70 | "1; SELECT * FROM Users", 71 | "' OR id IS NOT NULL OR id = '", 72 | "username' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'--", 73 | "' OR '1'='1' /*", 74 | "' UNION ALL SELECT NULL, NULL, NULL, CONCAT(username,':',password) FROM Users--", 75 | "' AND (SELECT * FROM (SELECT(SLEEP(5)))bAKL) AND 'vRxe'='vRxe", 76 | "'; WAITFOR DELAY '0:0:5'--", 77 | "The quick brown fox jumped over the lazy dog" 78 | }; 79 | 80 | for (int i = 0; i < 8; i++) Console.WriteLine(""); 81 | Console.WriteLine("Sanitizing input strings"); 82 | foreach (string attack in attacks) 83 | Console.WriteLine("| " + attack + " | Sanitized: " + _Database.SanitizeString(attack)); 84 | 85 | #endregion 86 | 87 | #region Drop-Table 88 | 89 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 90 | Console.WriteLine("Dropping table '" + _Table + "'..."); 91 | _Database.DropTable(_Table); 92 | Console.WriteLine("Press ENTER to continue..."); 93 | Console.ReadLine(); 94 | 95 | #endregion 96 | 97 | #region Create-Table 98 | 99 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 100 | Console.WriteLine("Creating table '" + _Table + "'..."); 101 | List columns = new List(); 102 | columns.Add(new Column("id", true, DataTypeEnum.Int, 11, null, false)); 103 | columns.Add(new Column("firstname", false, DataTypeEnum.Nvarchar, 30, null, false)); 104 | columns.Add(new Column("lastname", false, DataTypeEnum.Nvarchar, 30, null, false)); 105 | columns.Add(new Column("age", false, DataTypeEnum.Int, 11, null, true)); 106 | columns.Add(new Column("value", false, DataTypeEnum.Long, 12, null, true)); 107 | columns.Add(new Column("birthday", false, DataTypeEnum.DateTime, null, null, true)); 108 | columns.Add(new Column("hourly", false, DataTypeEnum.Decimal, 18, 2, true)); 109 | columns.Add(new Column("localtime", false, DataTypeEnum.DateTimeOffset, null, null, true)); 110 | columns.Add(new Column("picture", false, DataTypeEnum.Blob, true)); 111 | columns.Add(new Column("guid", false, DataTypeEnum.Guid, true)); 112 | columns.Add(new Column("active", false, DataTypeEnum.Boolean, true)); 113 | 114 | _Database.CreateTable(_Table, columns); 115 | Console.WriteLine("Press ENTER to continue..."); 116 | Console.ReadLine(); 117 | 118 | #endregion 119 | 120 | #region Check-Existence-and-Describe 121 | 122 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 123 | Console.WriteLine("Table '" + _Table + "' exists: " + _Database.TableExists(_Table)); 124 | Console.WriteLine("Table '" + _Table + "' configuration:"); 125 | columns = _Database.DescribeTable(_Table); 126 | foreach (Column col in columns) Console.WriteLine(col.ToString()); 127 | Console.WriteLine("Press ENTER to continue..."); 128 | Console.ReadLine(); 129 | 130 | #endregion 131 | 132 | #region Load-Update-Retrieve-Delete 133 | 134 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 135 | Console.WriteLine("Loading rows..."); 136 | LoadRows(); 137 | Console.WriteLine("Press ENTER to continue..."); 138 | Console.ReadLine(); 139 | 140 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 141 | Console.WriteLine("Loading multiple rows..."); 142 | LoadMultipleRows(); 143 | Console.WriteLine("Press ENTER to continue..."); 144 | Console.ReadLine(); 145 | 146 | Console.WriteLine("Checking existence..."); 147 | ExistsRows(); 148 | Console.WriteLine("Press ENTER to continue..."); 149 | Console.ReadLine(); 150 | 151 | Console.WriteLine("Counting age..."); 152 | CountAge(); 153 | Console.WriteLine("Press ENTER to continue..."); 154 | Console.ReadLine(); 155 | 156 | Console.WriteLine("Summing age..."); 157 | SumAge(); 158 | Console.WriteLine("Press ENTER to continue..."); 159 | Console.ReadLine(); 160 | 161 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 162 | Console.WriteLine("Updating rows..."); 163 | UpdateRows(); 164 | Console.WriteLine("Press ENTER to continue..."); 165 | Console.ReadLine(); 166 | 167 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 168 | Console.WriteLine("Retrieving rows..."); 169 | RetrieveRows(); 170 | Console.WriteLine("Press ENTER to continue..."); 171 | Console.ReadLine(); 172 | 173 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 174 | Console.WriteLine("Retrieving rows with special character..."); 175 | RetrieveRowsWithSpecialCharacter(); 176 | Console.WriteLine("Press ENTER to continue..."); 177 | Console.ReadLine(); 178 | 179 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 180 | Console.WriteLine("Retrieving rows by index..."); 181 | RetrieveRowsByIndex(); 182 | Console.WriteLine("Press ENTER to continue..."); 183 | Console.ReadLine(); 184 | 185 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 186 | Console.WriteLine("Retrieving rows by between..."); 187 | RetrieveRowsByBetween(); 188 | Console.WriteLine("Press ENTER to continue..."); 189 | Console.ReadLine(); 190 | 191 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 192 | Console.WriteLine("Retrieving sorted rows..."); 193 | RetrieveRowsSorted(); 194 | Console.WriteLine("Press ENTER to continue..."); 195 | Console.ReadLine(); 196 | 197 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 198 | Console.WriteLine("Deleting rows..."); 199 | DeleteRows(); 200 | Console.WriteLine("Press ENTER to continue"); 201 | Console.ReadLine(); 202 | 203 | #endregion 204 | 205 | #region Cause-Exception 206 | 207 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 208 | Console.WriteLine("Testing exception..."); 209 | 210 | try 211 | { 212 | _Database.Query("SELECT * FROM " + _Table + "((("); 213 | } 214 | catch (Exception e) 215 | { 216 | Console.WriteLine("Caught exception: " + e.Message); 217 | Console.WriteLine("Query: " + e.Data["Query"]); 218 | } 219 | 220 | #endregion 221 | 222 | #region Drop-Table 223 | 224 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 225 | Console.WriteLine("Dropping table..."); 226 | _Database.DropTable(_Table); 227 | Console.ReadLine(); 228 | 229 | #endregion 230 | } 231 | catch (Exception e) 232 | { 233 | Console.WriteLine(e.ToString()); 234 | } 235 | } 236 | 237 | static void LoadRows() 238 | { 239 | for (int i = 0; i < 50; i++) 240 | { 241 | Dictionary d = new Dictionary(); 242 | d.Add("firstname", "first" + i); 243 | d.Add("lastname", "last" + i); 244 | d.Add("age", i); 245 | d.Add("value", i * 1000); 246 | d.Add("birthday", DateTime.Now); 247 | d.Add("hourly", 123.456); 248 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 249 | d.Add("picture", _FileBytes); 250 | d.Add("guid", Guid.NewGuid()); 251 | d.Add("active", (i % 2 > 0)); 252 | 253 | _Database.Insert(_Table, d); 254 | } 255 | 256 | for (int i = 0; i < 10; i++) 257 | { 258 | Dictionary d = new Dictionary(); 259 | d.Add("firstname", "firsté" + i); 260 | d.Add("lastname", "lastШЋЖŠĆŽ" + i); 261 | d.Add("age", i); 262 | d.Add("value", i * 1000); 263 | d.Add("birthday", DateTime.Now); 264 | d.Add("hourly", 123.456); 265 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 266 | d.Add("guid", Guid.NewGuid()); 267 | d.Add("active", (i % 2 > 0)); 268 | 269 | _Database.Insert(_Table, d); 270 | } 271 | } 272 | 273 | static void LoadMultipleRows() 274 | { 275 | List> dicts = new List>(); 276 | 277 | for (int i = 0; i < 50; i++) 278 | { 279 | Dictionary d = new Dictionary(); 280 | d.Add("firstname", "firstmultiple" + i); 281 | d.Add("lastname", "lastmultiple" + i); 282 | d.Add("age", i); 283 | d.Add("value", i * 1000); 284 | d.Add("birthday", DateTime.Now); 285 | d.Add("hourly", 123.456); 286 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 287 | d.Add("picture", _FileBytes); 288 | d.Add("guid", Guid.NewGuid()); 289 | d.Add("active", (i % 2 > 0)); 290 | 291 | dicts.Add(d); 292 | } 293 | 294 | /* 295 | * 296 | * Uncomment this block if you wish to validate that inconsistent dictionary keys 297 | * will throw an argument exception. 298 | * 299 | Dictionary e = new Dictionary(); 300 | e.Add("firstnamefoo", "firstmultiple" + 1000); 301 | e.Add("lastname", "lastmultiple" + 1000); 302 | e.Add("age", 100); 303 | e.Add("value", 1000); 304 | e.Add("birthday", DateTime.Now); 305 | e.Add("hourly", 123.456); 306 | dicts.Add(e); 307 | * 308 | */ 309 | 310 | _Database.InsertMultiple(_Table, dicts); 311 | } 312 | 313 | static void ExistsRows() 314 | { 315 | Expr e = new Expr("firstname", OperatorEnum.IsNotNull, null); 316 | Console.WriteLine("Exists: " + _Database.Exists(_Table, e)); 317 | } 318 | 319 | static void CountAge() 320 | { 321 | Expr e = new Expr("age", OperatorEnum.GreaterThan, 25); 322 | Console.WriteLine("Age count: " + _Database.Count(_Table, e)); 323 | } 324 | 325 | static void SumAge() 326 | { 327 | Expr e = new Expr("age", OperatorEnum.GreaterThan, 0); 328 | Console.WriteLine("Age sum: " + _Database.Sum(_Table, "age", e)); 329 | } 330 | 331 | static void UpdateRows() 332 | { 333 | for (int i = 10; i < 20; i++) 334 | { 335 | Dictionary d = new Dictionary(); 336 | d.Add("firstname", "first" + i + "-updated"); 337 | d.Add("lastname", "last" + i + "-updated"); 338 | d.Add("age", i); 339 | d.Add("birthday", null); 340 | 341 | Expr e = new Expr("id", OperatorEnum.Equals, i); 342 | _Database.Update(_Table, d, e); 343 | } 344 | } 345 | 346 | static void RetrieveRows() 347 | { 348 | List returnFields = new List { "firstname", "lastname", "age", "picture" }; 349 | 350 | for (int i = 30; i < 40; i++) 351 | { 352 | Expr e = new Expr 353 | { 354 | Left = new Expr("id", OperatorEnum.LessThan, i), 355 | Operator = OperatorEnum.And, 356 | Right = new Expr("age", OperatorEnum.LessThan, i) 357 | }; 358 | 359 | // 360 | // Yes, personId and age should be the same, however, the example 361 | // is here to show how to build a nested expression 362 | // 363 | 364 | ResultOrder[] resultOrder = new ResultOrder[1]; 365 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 366 | 367 | DataTable result = _Database.Select(_Table, 0, 3, returnFields, e, resultOrder); 368 | if (result != null && result.Rows != null && result.Rows.Count > 0) 369 | { 370 | foreach (DataRow row in result.Rows) 371 | { 372 | byte[] data = (byte[])(row["picture"]); 373 | Console.WriteLine("Picture data length " + data.Length + " vs original length " + _FileBytes.Length); 374 | } 375 | } 376 | } 377 | } 378 | 379 | static void RetrieveRowsWithSpecialCharacter() 380 | { 381 | List returnFields = new List { "firstname", "lastname", "age" }; 382 | 383 | Expr e = new Expr("firstname", OperatorEnum.StartsWith, "firsté"); 384 | 385 | ResultOrder[] resultOrder = new ResultOrder[1]; 386 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 387 | 388 | DataTable result = _Database.Select(_Table, 0, 5, returnFields, e, resultOrder); 389 | if (result != null && result.Rows != null && result.Rows.Count > 0) 390 | { 391 | foreach (DataRow row in result.Rows) 392 | { 393 | Console.WriteLine("Person: " + row["firstname"] + " " + row["lastname"] + " age: " + row["age"]); 394 | } 395 | } 396 | } 397 | 398 | static void RetrieveRowsByIndex() 399 | { 400 | List returnFields = new List { "firstname", "lastname", "age" }; 401 | 402 | for (int i = 10; i < 20; i++) 403 | { 404 | Expr e = new Expr 405 | { 406 | Left = new Expr("id", OperatorEnum.GreaterThan, 1), 407 | Operator = OperatorEnum.And, 408 | Right = new Expr("age", OperatorEnum.LessThan, 50) 409 | }; 410 | 411 | // 412 | // Yes, personId and age should be the same, however, the example 413 | // is here to show how to build a nested expression 414 | // 415 | 416 | ResultOrder[] resultOrder = new ResultOrder[1]; 417 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 418 | 419 | _Database.Select(_Table, (i - 10), 5, returnFields, e, resultOrder); 420 | } 421 | } 422 | 423 | static void RetrieveRowsByBetween() 424 | { 425 | List returnFields = new List { "firstname", "lastname", "age" }; 426 | Expr e = Expr.Between("id", new List { 10, 20 }); 427 | Console.WriteLine("Expression: " + e.ToString()); 428 | _Database.Select(_Table, null, null, returnFields, e); 429 | } 430 | 431 | static void RetrieveRowsSorted() 432 | { 433 | List returnFields = new List { "firstname", "lastname", "age" }; 434 | Expr e = Expr.Between("id", new List { 10, 20 }); 435 | Console.WriteLine("Expression: " + e.ToString()); 436 | ResultOrder[] resultOrder = new ResultOrder[1]; 437 | resultOrder[0] = new ResultOrder("firstname", OrderDirectionEnum.Ascending); 438 | _Database.Select(_Table, null, null, returnFields, e, resultOrder); 439 | } 440 | 441 | private static void DeleteRows() 442 | { 443 | for (int i = 20; i < 30; i++) 444 | { 445 | Expr e = new Expr("id", OperatorEnum.Equals, i); 446 | _Database.Delete(_Table, e); 447 | } 448 | } 449 | 450 | private static string StackToString() 451 | { 452 | string ret = ""; 453 | 454 | StackTrace t = new StackTrace(); 455 | for (int i = 0; i < t.FrameCount; i++) 456 | { 457 | if (i == 0) 458 | { 459 | ret += t.GetFrame(i).GetMethod().Name; 460 | } 461 | else 462 | { 463 | ret += " <= " + t.GetFrame(i).GetMethod().Name; 464 | } 465 | } 466 | 467 | return ret; 468 | } 469 | 470 | private static void Logger(string msg) 471 | { 472 | Console.WriteLine(msg); 473 | } 474 | } 475 | } 476 | -------------------------------------------------------------------------------- /src/Test.SqlServer/Test.SqlServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.SqlServer/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.SqlServer/headshot.png -------------------------------------------------------------------------------- /src/Test.SqlServerAsync/Test.SqlServerAsync.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.SqlServerAsync/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.SqlServerAsync/headshot.png -------------------------------------------------------------------------------- /src/Test.Sqlite/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Test.Sqlite 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using DatabaseWrapper.Sqlite; 12 | using DatabaseWrapper.Core; 13 | using ExpressionTree; 14 | 15 | class Program 16 | { 17 | static DatabaseSettings _Settings; 18 | static DatabaseClient _Database; 19 | static string _Table = "person"; 20 | static byte[] _FileBytes = File.ReadAllBytes("./headshot.png"); 21 | 22 | static void Main(string[] args) 23 | { 24 | try 25 | { 26 | #region Setup-Database 27 | 28 | Console.Write("Filename: "); 29 | string filename = Console.ReadLine(); 30 | if (String.IsNullOrEmpty(filename)) return; 31 | _Settings = new DatabaseSettings(filename); 32 | _Settings.Debug.Logger = Logger; 33 | _Settings.Debug.EnableForQueries = true; 34 | _Settings.Debug.EnableForResults = true; 35 | 36 | _Database = new DatabaseClient(_Settings); 37 | 38 | #endregion 39 | 40 | #region Sanitize-Data 41 | 42 | string[] attacks = { 43 | "' OR '1'='1", 44 | "'; DROP TABLE Users; --", 45 | "' UNION SELECT username, password FROM Users--", 46 | "' OR 1=1--", 47 | "admin' --", 48 | "'; EXEC xp_cmdshell 'net user';--", 49 | "' OR 'x'='x", 50 | "1 OR 1=1", 51 | "1; SELECT * FROM Users", 52 | "' OR id IS NOT NULL OR id = '", 53 | "username' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'--", 54 | "' OR '1'='1' /*", 55 | "' UNION ALL SELECT NULL, NULL, NULL, CONCAT(username,':',password) FROM Users--", 56 | "' AND (SELECT * FROM (SELECT(SLEEP(5)))bAKL) AND 'vRxe'='vRxe", 57 | "'; WAITFOR DELAY '0:0:5'--", 58 | "The quick brown fox jumped over the lazy dog" 59 | }; 60 | 61 | for (int i = 0; i < 8; i++) Console.WriteLine(""); 62 | Console.WriteLine("Sanitizing input strings"); 63 | foreach (string attack in attacks) 64 | Console.WriteLine("| " + attack + " | Sanitized: " + _Database.SanitizeString(attack)); 65 | 66 | #endregion 67 | 68 | #region Drop-Table 69 | 70 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 71 | Console.WriteLine("Dropping table '" + _Table + "'..."); 72 | _Database.DropTable(_Table); 73 | Console.WriteLine("Press ENTER to continue..."); 74 | Console.ReadLine(); 75 | 76 | #endregion 77 | 78 | #region Create-Table 79 | 80 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 81 | Console.WriteLine("Creating table '" + _Table + "'..."); 82 | List columns = new List(); 83 | columns.Add(new Column("id", true, DataTypeEnum.Int, 11, null, false)); 84 | columns.Add(new Column("firstName", false, DataTypeEnum.Nvarchar, 30, null, false)); 85 | columns.Add(new Column("lastName", false, DataTypeEnum.Nvarchar, 30, null, false)); 86 | columns.Add(new Column("age", false, DataTypeEnum.Int, 11, null, true)); 87 | columns.Add(new Column("value", false, DataTypeEnum.Long, 12, null, true)); 88 | columns.Add(new Column("birthday", false, DataTypeEnum.DateTime, null, null, true)); 89 | columns.Add(new Column("hourly", false, DataTypeEnum.Decimal, 18, 2, true)); 90 | columns.Add(new Column("localtime", false, DataTypeEnum.DateTimeOffset, null, null, true)); 91 | columns.Add(new Column("picture", false, DataTypeEnum.Blob, true)); 92 | columns.Add(new Column("guid", false, DataTypeEnum.Guid, true)); 93 | columns.Add(new Column("active", false, DataTypeEnum.Boolean, true)); 94 | 95 | _Database.CreateTable(_Table, columns); 96 | Console.WriteLine("Press ENTER to continue..."); 97 | Console.ReadLine(); 98 | 99 | #endregion 100 | 101 | #region Check-Existence-and-Describe 102 | 103 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 104 | Console.WriteLine("Table '" + _Table + "' exists: " + _Database.TableExists(_Table)); 105 | Console.WriteLine("Table '" + _Table + "' configuration:"); 106 | columns = _Database.DescribeTable(_Table); 107 | foreach (Column col in columns) Console.WriteLine(col.ToString()); 108 | Console.WriteLine("Press ENTER to continue..."); 109 | Console.ReadLine(); 110 | 111 | #endregion 112 | 113 | #region Load-Update-Retrieve-Delete 114 | 115 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 116 | Console.WriteLine("Loading rows..."); 117 | LoadRows(); 118 | Console.WriteLine("Press ENTER to continue..."); 119 | Console.ReadLine(); 120 | 121 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 122 | Console.WriteLine("Loading multiple rows..."); 123 | LoadMultipleRows(); 124 | Console.WriteLine("Press ENTER to continue..."); 125 | Console.ReadLine(); 126 | 127 | Console.WriteLine("Checking existence..."); 128 | ExistsRows(); 129 | Console.WriteLine("Press ENTER to continue..."); 130 | Console.ReadLine(); 131 | 132 | Console.WriteLine("Counting age..."); 133 | CountAge(); 134 | Console.WriteLine("Press ENTER to continue..."); 135 | Console.ReadLine(); 136 | 137 | Console.WriteLine("Summing age..."); 138 | SumAge(); 139 | Console.WriteLine("Press ENTER to continue..."); 140 | Console.ReadLine(); 141 | 142 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 143 | Console.WriteLine("Updating rows..."); 144 | UpdateRows(); 145 | Console.WriteLine("Press ENTER to continue..."); 146 | Console.ReadLine(); 147 | 148 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 149 | Console.WriteLine("Retrieving rows..."); 150 | RetrieveRows(); 151 | Console.WriteLine("Press ENTER to continue..."); 152 | Console.ReadLine(); 153 | 154 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 155 | Console.WriteLine("Retrieving rows with special character..."); 156 | RetrieveRowsWithSpecialCharacter(); 157 | Console.WriteLine("Press ENTER to continue..."); 158 | Console.ReadLine(); 159 | 160 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 161 | Console.WriteLine("Retrieving rows by index..."); 162 | RetrieveRowsByIndex(); 163 | Console.WriteLine("Press ENTER to continue..."); 164 | Console.ReadLine(); 165 | 166 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 167 | Console.WriteLine("Retrieving rows by between..."); 168 | RetrieveRowsByBetween(); 169 | Console.WriteLine("Press ENTER to continue..."); 170 | Console.ReadLine(); 171 | 172 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 173 | Console.WriteLine("Retrieving sorted rows..."); 174 | RetrieveRowsSorted(); 175 | Console.WriteLine("Press ENTER to continue..."); 176 | Console.ReadLine(); 177 | 178 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 179 | Console.WriteLine("Deleting rows..."); 180 | DeleteRows(); 181 | Console.WriteLine("Press ENTER to continue"); 182 | Console.ReadLine(); 183 | 184 | #endregion 185 | 186 | #region Cause-Exception 187 | 188 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 189 | Console.WriteLine("Testing exception..."); 190 | 191 | try 192 | { 193 | _Database.Query("SELECT * FROM person((("); 194 | } 195 | catch (Exception e) 196 | { 197 | Console.WriteLine("Caught exception: " + e.Message); 198 | Console.WriteLine("Query: " + e.Data["Query"]); 199 | } 200 | 201 | #endregion 202 | 203 | #region Drop-Table 204 | 205 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 206 | Console.WriteLine("Dropping table..."); 207 | _Database.DropTable(_Table); 208 | Console.ReadLine(); 209 | 210 | #endregion 211 | } 212 | catch (Exception e) 213 | { 214 | Console.WriteLine(e.ToString()); 215 | } 216 | } 217 | 218 | static void LoadRows() 219 | { 220 | for (int i = 0; i < 50; i++) 221 | { 222 | Dictionary d = new Dictionary(); 223 | d.Add("firstName", "first" + i); 224 | d.Add("lastName", "last" + i); 225 | d.Add("age", i); 226 | d.Add("value", i * 1000); 227 | d.Add("birthday", DateTime.Now); 228 | d.Add("hourly", 123.456); 229 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 230 | d.Add("picture", _FileBytes); 231 | d.Add("guid", Guid.NewGuid()); 232 | d.Add("active", (i % 2 > 0)); 233 | 234 | _Database.Insert(_Table, d); 235 | } 236 | 237 | for (int i = 0; i < 10; i++) 238 | { 239 | Dictionary d = new Dictionary(); 240 | d.Add("firstname", "firsté" + i); 241 | d.Add("lastname", "lastШЋЖŠĆŽ" + i); 242 | d.Add("age", i); 243 | d.Add("value", i * 1000); 244 | d.Add("birthday", DateTime.Now); 245 | d.Add("hourly", 123.456); 246 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 247 | d.Add("guid", Guid.NewGuid()); 248 | d.Add("active", (i % 2 > 0)); 249 | 250 | _Database.Insert(_Table, d); 251 | } 252 | } 253 | 254 | static void LoadMultipleRows() 255 | { 256 | List> dicts = new List>(); 257 | 258 | for (int i = 0; i < 50; i++) 259 | { 260 | Dictionary d = new Dictionary(); 261 | d.Add("firstname", "firstmultiple" + i); 262 | d.Add("lastname", "lastmultiple" + i); 263 | d.Add("age", i); 264 | d.Add("value", i * 1000); 265 | d.Add("birthday", DateTime.Now); 266 | d.Add("hourly", 123.456); 267 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 268 | d.Add("picture", _FileBytes); 269 | d.Add("guid", Guid.NewGuid()); 270 | d.Add("active", (i % 2 > 0)); 271 | 272 | dicts.Add(d); 273 | } 274 | 275 | /* 276 | * 277 | * Uncomment this block if you wish to validate that inconsistent dictionary keys 278 | * will throw an argument exception. 279 | * 280 | Dictionary e = new Dictionary(); 281 | e.Add("firstnamefoo", "firstmultiple" + 1000); 282 | e.Add("lastname", "lastmultiple" + 1000); 283 | e.Add("age", 100); 284 | e.Add("value", 1000); 285 | e.Add("birthday", DateTime.Now); 286 | e.Add("hourly", 123.456); 287 | dicts.Add(e); 288 | * 289 | */ 290 | 291 | _Database.InsertMultiple(_Table, dicts); 292 | } 293 | 294 | static void ExistsRows() 295 | { 296 | Expr e = new Expr("firstName", OperatorEnum.IsNotNull, null); 297 | Console.WriteLine("Exists: " + _Database.Exists(_Table, e)); 298 | } 299 | 300 | static void CountAge() 301 | { 302 | Expr e = new Expr("age", OperatorEnum.GreaterThan, 25); 303 | Console.WriteLine("Age count: " + _Database.Count(_Table, e)); 304 | } 305 | 306 | static void SumAge() 307 | { 308 | Expr e = new Expr("age", OperatorEnum.GreaterThan, 0); 309 | Console.WriteLine("Age sum: " + _Database.Sum(_Table, "age", e)); 310 | } 311 | 312 | static void UpdateRows() 313 | { 314 | for (int i = 10; i < 20; i++) 315 | { 316 | Dictionary d = new Dictionary(); 317 | d.Add("firstName", "first" + i + "-updated"); 318 | d.Add("lastName", "last" + i + "-updated"); 319 | d.Add("age", i); 320 | d.Add("birthday", null); 321 | 322 | Expr e = new Expr("id", OperatorEnum.Equals, i); 323 | _Database.Update(_Table, d, e); 324 | } 325 | } 326 | 327 | static void RetrieveRows() 328 | { 329 | List returnFields = new List { "firstName", "lastName", "age", "picture" }; 330 | 331 | for (int i = 30; i < 40; i++) 332 | { 333 | Expr e = new Expr 334 | { 335 | Left = new Expr("id", OperatorEnum.LessThan, i), 336 | Operator = OperatorEnum.And, 337 | Right = new Expr("age", OperatorEnum.LessThan, i) 338 | }; 339 | 340 | // 341 | // Yes, personId and age should be the same, however, the example 342 | // is here to show how to build a nested expression 343 | // 344 | 345 | DataTable result = _Database.Select(_Table, null, 3, returnFields, e); 346 | if (result != null && result.Rows != null && result.Rows.Count > 0) 347 | { 348 | foreach (DataRow row in result.Rows) 349 | { 350 | byte[] data = (byte[])(row["picture"]); 351 | Console.WriteLine("Picture data length " + data.Length + " vs original length " + _FileBytes.Length); 352 | } 353 | } 354 | } 355 | } 356 | 357 | static void RetrieveRowsWithSpecialCharacter() 358 | { 359 | List returnFields = new List { "firstname", "lastname", "age" }; 360 | 361 | Expr e = new Expr("firstname", OperatorEnum.StartsWith, "firsté"); 362 | 363 | DataTable result = _Database.Select(_Table, 0, 5, returnFields, e); 364 | if (result != null && result.Rows != null && result.Rows.Count > 0) 365 | { 366 | foreach (DataRow row in result.Rows) 367 | { 368 | Console.WriteLine("Person: " + row["firstname"] + " " + row["lastname"] + " age: " + row["age"]); 369 | } 370 | } 371 | } 372 | 373 | static void RetrieveRowsByIndex() 374 | { 375 | List returnFields = new List { "firstName", "lastName", "age" }; 376 | 377 | for (int i = 10; i < 20; i++) 378 | { 379 | Expr e = new Expr 380 | { 381 | Left = new Expr("id", OperatorEnum.GreaterThan, 1), 382 | Operator = OperatorEnum.And, 383 | Right = new Expr("age", OperatorEnum.LessThan, 50) 384 | }; 385 | 386 | // 387 | // Yes, personId and age should be the same, however, the example 388 | // is here to show how to build a nested expression 389 | // 390 | 391 | ResultOrder[] order = new ResultOrder[1]; 392 | order[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 393 | 394 | _Database.Select(_Table, (i - 10), 5, returnFields, e); 395 | } 396 | } 397 | 398 | static void RetrieveRowsByBetween() 399 | { 400 | List returnFields = new List { "firstName", "lastName", "age" }; 401 | Expr e = Expr.Between("id", new List { 10, 20 }); 402 | Console.WriteLine("Expression: " + e.ToString()); 403 | _Database.Select(_Table, null, null, returnFields, e); 404 | } 405 | 406 | static void RetrieveRowsSorted() 407 | { 408 | List returnFields = new List { "firstName", "lastName", "age" }; 409 | Expr e = Expr.Between("id", new List { 10, 20 }); 410 | Console.WriteLine("Expression: " + e.ToString()); 411 | ResultOrder[] resultOrder = new ResultOrder[2]; 412 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Descending); 413 | resultOrder[1] = new ResultOrder("firstName", OrderDirectionEnum.Ascending); 414 | _Database.Select(_Table, null, null, returnFields, e, resultOrder); 415 | } 416 | 417 | private static void DeleteRows() 418 | { 419 | for (int i = 20; i < 30; i++) 420 | { 421 | Expr e = new Expr("id", OperatorEnum.Equals, i); 422 | _Database.Delete(_Table, e); 423 | } 424 | } 425 | 426 | private static string StackToString() 427 | { 428 | string ret = ""; 429 | 430 | StackTrace t = new StackTrace(); 431 | for (int i = 0; i < t.FrameCount; i++) 432 | { 433 | if (i == 0) 434 | { 435 | ret += t.GetFrame(i).GetMethod().Name; 436 | } 437 | else 438 | { 439 | ret += " <= " + t.GetFrame(i).GetMethod().Name; 440 | } 441 | } 442 | 443 | return ret; 444 | } 445 | 446 | private static void ExceptionConsole(string method, string text, Exception e) 447 | { 448 | var st = new StackTrace(e, true); 449 | var frame = st.GetFrame(0); 450 | int line = frame.GetFileLineNumber(); 451 | string filename = frame.GetFileName(); 452 | 453 | Console.WriteLine("---"); 454 | Console.WriteLine("An exception was encountered which triggered this message."); 455 | Console.WriteLine(" Method: " + method); 456 | Console.WriteLine(" Text: " + text); 457 | Console.WriteLine(" Type: " + e.GetType().ToString()); 458 | Console.WriteLine(" Data: " + e.Data); 459 | Console.WriteLine(" Inner: " + e.InnerException); 460 | Console.WriteLine(" Message: " + e.Message); 461 | Console.WriteLine(" Source: " + e.Source); 462 | Console.WriteLine(" StackTrace: " + e.StackTrace); 463 | Console.WriteLine(" Stack: " + StackToString()); 464 | Console.WriteLine(" Line: " + line); 465 | Console.WriteLine(" File: " + filename); 466 | Console.WriteLine(" ToString: " + e.ToString()); 467 | Console.WriteLine("---"); 468 | 469 | return; 470 | } 471 | 472 | private static void Logger(string msg) 473 | { 474 | Console.WriteLine(msg); 475 | } 476 | } 477 | } 478 | -------------------------------------------------------------------------------- /src/Test.Sqlite/Test.Sqlite.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.Sqlite/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.Sqlite/headshot.png -------------------------------------------------------------------------------- /src/Test.SqliteAsync/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Test.Sqlite 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using DatabaseWrapper.Sqlite; 12 | using DatabaseWrapper.Core; 13 | using ExpressionTree; 14 | 15 | class Program 16 | { 17 | static DatabaseSettings _Settings; 18 | static DatabaseClient _Database; 19 | static string _Table = "person"; 20 | static byte[] _FileBytes = File.ReadAllBytes("./headshot.png"); 21 | 22 | static async Task Main(string[] args) 23 | { 24 | try 25 | { 26 | #region Setup-Database 27 | 28 | Console.Write("Filename: "); 29 | string filename = Console.ReadLine(); 30 | if (String.IsNullOrEmpty(filename)) return; 31 | _Settings = new DatabaseSettings(filename); 32 | _Settings.Debug.Logger = Logger; 33 | _Settings.Debug.EnableForQueries = true; 34 | _Settings.Debug.EnableForResults = true; 35 | 36 | _Database = new DatabaseClient(_Settings); 37 | 38 | #endregion 39 | 40 | #region Sanitize-Data 41 | 42 | string[] attacks = { 43 | "' OR '1'='1", 44 | "'; DROP TABLE Users; --", 45 | "' UNION SELECT username, password FROM Users--", 46 | "' OR 1=1--", 47 | "admin' --", 48 | "'; EXEC xp_cmdshell 'net user';--", 49 | "' OR 'x'='x", 50 | "1 OR 1=1", 51 | "1; SELECT * FROM Users", 52 | "' OR id IS NOT NULL OR id = '", 53 | "username' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'--", 54 | "' OR '1'='1' /*", 55 | "' UNION ALL SELECT NULL, NULL, NULL, CONCAT(username,':',password) FROM Users--", 56 | "' AND (SELECT * FROM (SELECT(SLEEP(5)))bAKL) AND 'vRxe'='vRxe", 57 | "'; WAITFOR DELAY '0:0:5'--", 58 | "The quick brown fox jumped over the lazy dog" 59 | }; 60 | 61 | for (int i = 0; i < 8; i++) Console.WriteLine(""); 62 | Console.WriteLine("Sanitizing input strings"); 63 | foreach (string attack in attacks) 64 | Console.WriteLine("| " + attack + " | Sanitized: " + _Database.SanitizeString(attack)); 65 | 66 | #endregion 67 | 68 | #region Drop-Table 69 | 70 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 71 | Console.WriteLine("Dropping table '" + _Table + "'..."); 72 | await _Database.DropTableAsync(_Table); 73 | Console.WriteLine("Press ENTER to continue..."); 74 | Console.ReadLine(); 75 | 76 | #endregion 77 | 78 | #region Create-Table 79 | 80 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 81 | Console.WriteLine("Creating table '" + _Table + "'..."); 82 | List columns = new List(); 83 | columns.Add(new Column("id", true, DataTypeEnum.Int, 11, null, false)); 84 | columns.Add(new Column("firstName", false, DataTypeEnum.Nvarchar, 30, null, false)); 85 | columns.Add(new Column("lastName", false, DataTypeEnum.Nvarchar, 30, null, false)); 86 | columns.Add(new Column("age", false, DataTypeEnum.Int, 11, null, true)); 87 | columns.Add(new Column("value", false, DataTypeEnum.Long, 12, null, true)); 88 | columns.Add(new Column("birthday", false, DataTypeEnum.DateTime, null, null, true)); 89 | columns.Add(new Column("hourly", false, DataTypeEnum.Decimal, 18, 2, true)); 90 | columns.Add(new Column("localtime", false, DataTypeEnum.DateTimeOffset, null, null, true)); 91 | columns.Add(new Column("picture", false, DataTypeEnum.Blob, true)); 92 | columns.Add(new Column("guid", false, DataTypeEnum.Guid, true)); 93 | columns.Add(new Column("active", false, DataTypeEnum.Boolean, true)); 94 | 95 | await _Database.CreateTableAsync(_Table, columns); 96 | Console.WriteLine("Press ENTER to continue..."); 97 | Console.ReadLine(); 98 | 99 | #endregion 100 | 101 | #region Check-Existence-and-Describe 102 | 103 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 104 | Console.WriteLine("Table '" + _Table + "' exists: " + await _Database.TableExistsAsync(_Table)); 105 | Console.WriteLine("Table '" + _Table + "' configuration:"); 106 | columns = await _Database.DescribeTableAsync(_Table); 107 | foreach (Column col in columns) Console.WriteLine(col.ToString()); 108 | Console.WriteLine("Press ENTER to continue..."); 109 | Console.ReadLine(); 110 | 111 | #endregion 112 | 113 | #region Load-Update-Retrieve-Delete 114 | 115 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 116 | Console.WriteLine("Loading rows..."); 117 | await LoadRows(); 118 | Console.WriteLine("Press ENTER to continue..."); 119 | Console.ReadLine(); 120 | 121 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 122 | Console.WriteLine("Loading multiple rows..."); 123 | await LoadMultipleRows(); 124 | Console.WriteLine("Press ENTER to continue..."); 125 | Console.ReadLine(); 126 | 127 | Console.WriteLine("Checking existence..."); 128 | await ExistsRows(); 129 | Console.WriteLine("Press ENTER to continue..."); 130 | Console.ReadLine(); 131 | 132 | Console.WriteLine("Counting age..."); 133 | await CountAge(); 134 | Console.WriteLine("Press ENTER to continue..."); 135 | Console.ReadLine(); 136 | 137 | Console.WriteLine("Summing age..."); 138 | await SumAge(); 139 | Console.WriteLine("Press ENTER to continue..."); 140 | Console.ReadLine(); 141 | 142 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 143 | Console.WriteLine("Updating rows..."); 144 | await UpdateRows(); 145 | Console.WriteLine("Press ENTER to continue..."); 146 | Console.ReadLine(); 147 | 148 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 149 | Console.WriteLine("Retrieving rows..."); 150 | await RetrieveRows(); 151 | Console.WriteLine("Press ENTER to continue..."); 152 | Console.ReadLine(); 153 | 154 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 155 | Console.WriteLine("Retrieving rows with special character..."); 156 | await RetrieveRowsWithSpecialCharacter(); 157 | Console.WriteLine("Press ENTER to continue..."); 158 | Console.ReadLine(); 159 | 160 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 161 | Console.WriteLine("Retrieving rows by index..."); 162 | await RetrieveRowsByIndex(); 163 | Console.WriteLine("Press ENTER to continue..."); 164 | Console.ReadLine(); 165 | 166 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 167 | Console.WriteLine("Retrieving rows by between..."); 168 | await RetrieveRowsByBetween(); 169 | Console.WriteLine("Press ENTER to continue..."); 170 | Console.ReadLine(); 171 | 172 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 173 | Console.WriteLine("Retrieving sorted rows..."); 174 | await RetrieveRowsSorted(); 175 | Console.WriteLine("Press ENTER to continue..."); 176 | Console.ReadLine(); 177 | 178 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 179 | Console.WriteLine("Deleting rows..."); 180 | await DeleteRows(); 181 | Console.WriteLine("Press ENTER to continue"); 182 | Console.ReadLine(); 183 | 184 | #endregion 185 | 186 | #region Cause-Exception 187 | 188 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 189 | Console.WriteLine("Testing exception..."); 190 | 191 | try 192 | { 193 | _Database.Query("SELECT * FROM person((("); 194 | } 195 | catch (Exception e) 196 | { 197 | Console.WriteLine("Caught exception: " + e.Message); 198 | Console.WriteLine("Query: " + e.Data["Query"]); 199 | } 200 | 201 | #endregion 202 | 203 | #region Drop-Table 204 | 205 | for (int i = 0; i < 24; i++) Console.WriteLine(""); 206 | Console.WriteLine("Dropping table..."); 207 | _Database.DropTable(_Table); 208 | Console.ReadLine(); 209 | 210 | #endregion 211 | } 212 | catch (Exception e) 213 | { 214 | Console.WriteLine(e.ToString()); 215 | } 216 | } 217 | 218 | static async Task LoadRows() 219 | { 220 | for (int i = 0; i < 50; i++) 221 | { 222 | Dictionary d = new Dictionary(); 223 | d.Add("firstname", "first" + i); 224 | d.Add("lastname", "last" + i); 225 | d.Add("age", i); 226 | d.Add("value", i * 1000); 227 | d.Add("birthday", DateTime.Now); 228 | d.Add("hourly", 123.456); 229 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 230 | d.Add("picture", _FileBytes); 231 | d.Add("guid", Guid.NewGuid()); 232 | d.Add("active", (i % 2 > 0)); 233 | 234 | await _Database.InsertAsync(_Table, d); 235 | } 236 | 237 | for (int i = 0; i < 10; i++) 238 | { 239 | Dictionary d = new Dictionary(); 240 | d.Add("firstname", "firsté" + i); 241 | d.Add("lastname", "lastШЋЖŠĆŽ" + i); 242 | d.Add("age", i); 243 | d.Add("value", i * 1000); 244 | d.Add("birthday", DateTime.Now); 245 | d.Add("hourly", 123.456); 246 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 247 | d.Add("guid", Guid.NewGuid()); 248 | d.Add("active", (i % 2 > 0)); 249 | 250 | await _Database.InsertAsync(_Table, d); 251 | } 252 | } 253 | 254 | static async Task LoadMultipleRows() 255 | { 256 | List> dicts = new List>(); 257 | 258 | for (int i = 0; i < 50; i++) 259 | { 260 | Dictionary d = new Dictionary(); 261 | d.Add("firstname", "firstmultiple" + i); 262 | d.Add("lastname", "lastmultiple" + i); 263 | d.Add("age", i); 264 | d.Add("value", i * 1000); 265 | d.Add("birthday", DateTime.Now); 266 | d.Add("hourly", 123.456); 267 | d.Add("localtime", new DateTimeOffset(2021, 4, 14, 01, 02, 03, new TimeSpan(7, 0, 0))); 268 | d.Add("picture", _FileBytes); 269 | d.Add("guid", Guid.NewGuid()); 270 | d.Add("active", (i % 2 > 0)); 271 | 272 | dicts.Add(d); 273 | } 274 | 275 | /* 276 | * 277 | * Uncomment this block if you wish to validate that inconsistent dictionary keys 278 | * will throw an argument exception. 279 | * 280 | Dictionary e = new Dictionary(); 281 | e.Add("firstnamefoo", "firstmultiple" + 1000); 282 | e.Add("lastname", "lastmultiple" + 1000); 283 | e.Add("age", 100); 284 | e.Add("value", 1000); 285 | e.Add("birthday", DateTime.Now); 286 | e.Add("hourly", 123.456); 287 | dicts.Add(e); 288 | * 289 | */ 290 | 291 | await _Database.InsertMultipleAsync(_Table, dicts); 292 | } 293 | 294 | static async Task ExistsRows() 295 | { 296 | Expr e = new Expr("firstname", OperatorEnum.IsNotNull, null); 297 | Console.WriteLine("Exists: " + await _Database.ExistsAsync(_Table, e)); 298 | } 299 | 300 | static async Task CountAge() 301 | { 302 | Expr e = new Expr("age", OperatorEnum.GreaterThan, 25); 303 | Console.WriteLine("Age count: " + await _Database.CountAsync(_Table, e)); 304 | } 305 | 306 | static async Task SumAge() 307 | { 308 | Expr e = new Expr("age", OperatorEnum.GreaterThan, 0); 309 | Console.WriteLine("Age sum: " + await _Database.SumAsync(_Table, "age", e)); 310 | } 311 | 312 | static async Task UpdateRows() 313 | { 314 | for (int i = 10; i < 20; i++) 315 | { 316 | Dictionary d = new Dictionary(); 317 | d.Add("firstname", "first" + i + "-updated"); 318 | d.Add("lastname", "last" + i + "-updated"); 319 | d.Add("age", i); 320 | d.Add("birthday", null); 321 | 322 | Expr e = new Expr("id", OperatorEnum.Equals, i); 323 | await _Database.UpdateAsync(_Table, d, e); 324 | } 325 | } 326 | 327 | static async Task RetrieveRows() 328 | { 329 | List returnFields = new List { "firstname", "lastname", "age", "picture" }; 330 | 331 | for (int i = 30; i < 40; i++) 332 | { 333 | Expr e = new Expr 334 | { 335 | Left = new Expr("id", OperatorEnum.LessThan, i), 336 | Operator = OperatorEnum.And, 337 | Right = new Expr("age", OperatorEnum.LessThan, i) 338 | }; 339 | 340 | // 341 | // Yes, personId and age should be the same, however, the example 342 | // is here to show how to build a nested expression 343 | // 344 | 345 | ResultOrder[] resultOrder = new ResultOrder[1]; 346 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 347 | 348 | DataTable result = await _Database.SelectAsync(_Table, 0, 3, returnFields, e, resultOrder); 349 | if (result != null && result.Rows != null && result.Rows.Count > 0) 350 | { 351 | foreach (DataRow row in result.Rows) 352 | { 353 | byte[] data = (byte[])(row["picture"]); 354 | Console.WriteLine("Picture data length " + data.Length + " vs original length " + _FileBytes.Length); 355 | } 356 | } 357 | } 358 | } 359 | 360 | static async Task RetrieveRowsWithSpecialCharacter() 361 | { 362 | List returnFields = new List { "firstname", "lastname", "age" }; 363 | 364 | Expr e = new Expr("firstname", OperatorEnum.StartsWith, "firsté"); 365 | 366 | ResultOrder[] resultOrder = new ResultOrder[1]; 367 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 368 | 369 | DataTable result = await _Database.SelectAsync(_Table, 0, 5, returnFields, e, resultOrder); 370 | if (result != null && result.Rows != null && result.Rows.Count > 0) 371 | { 372 | foreach (DataRow row in result.Rows) 373 | { 374 | Console.WriteLine("Person: " + row["firstname"] + " " + row["lastname"] + " age: " + row["age"]); 375 | } 376 | } 377 | } 378 | 379 | static async Task RetrieveRowsByIndex() 380 | { 381 | List returnFields = new List { "firstname", "lastname", "age" }; 382 | 383 | for (int i = 10; i < 20; i++) 384 | { 385 | Expr e = new Expr 386 | { 387 | Left = new Expr("id", OperatorEnum.GreaterThan, 1), 388 | Operator = OperatorEnum.And, 389 | Right = new Expr("age", OperatorEnum.LessThan, 50) 390 | }; 391 | 392 | // 393 | // Yes, personId and age should be the same, however, the example 394 | // is here to show how to build a nested expression 395 | // 396 | 397 | ResultOrder[] resultOrder = new ResultOrder[1]; 398 | resultOrder[0] = new ResultOrder("id", OrderDirectionEnum.Ascending); 399 | 400 | await _Database.SelectAsync(_Table, (i - 10), 5, returnFields, e, resultOrder); 401 | } 402 | } 403 | 404 | static async Task RetrieveRowsByBetween() 405 | { 406 | List returnFields = new List { "firstname", "lastname", "age" }; 407 | Expr e = Expr.Between("id", new List { 10, 20 }); 408 | Console.WriteLine("Expression: " + e.ToString()); 409 | await _Database.SelectAsync(_Table, null, null, returnFields, e); 410 | } 411 | 412 | static async Task RetrieveRowsSorted() 413 | { 414 | List returnFields = new List { "firstname", "lastname", "age" }; 415 | Expr e = Expr.Between("id", new List { 10, 20 }); 416 | Console.WriteLine("Expression: " + e.ToString()); 417 | ResultOrder[] resultOrder = new ResultOrder[1]; 418 | resultOrder[0] = new ResultOrder("firstname", OrderDirectionEnum.Ascending); 419 | await _Database.SelectAsync(_Table, null, null, returnFields, e, resultOrder); 420 | } 421 | 422 | private static async Task DeleteRows() 423 | { 424 | for (int i = 20; i < 30; i++) 425 | { 426 | Expr e = new Expr("id", OperatorEnum.Equals, i); 427 | await _Database.DeleteAsync(_Table, e); 428 | } 429 | } 430 | 431 | private static string StackToString() 432 | { 433 | string ret = ""; 434 | 435 | StackTrace t = new StackTrace(); 436 | for (int i = 0; i < t.FrameCount; i++) 437 | { 438 | if (i == 0) 439 | { 440 | ret += t.GetFrame(i).GetMethod().Name; 441 | } 442 | else 443 | { 444 | ret += " <= " + t.GetFrame(i).GetMethod().Name; 445 | } 446 | } 447 | 448 | return ret; 449 | } 450 | 451 | private static void ExceptionConsole(string method, string text, Exception e) 452 | { 453 | var st = new StackTrace(e, true); 454 | var frame = st.GetFrame(0); 455 | int line = frame.GetFileLineNumber(); 456 | string filename = frame.GetFileName(); 457 | 458 | Console.WriteLine("---"); 459 | Console.WriteLine("An exception was encountered which triggered this message."); 460 | Console.WriteLine(" Method: " + method); 461 | Console.WriteLine(" Text: " + text); 462 | Console.WriteLine(" Type: " + e.GetType().ToString()); 463 | Console.WriteLine(" Data: " + e.Data); 464 | Console.WriteLine(" Inner: " + e.InnerException); 465 | Console.WriteLine(" Message: " + e.Message); 466 | Console.WriteLine(" Source: " + e.Source); 467 | Console.WriteLine(" StackTrace: " + e.StackTrace); 468 | Console.WriteLine(" Stack: " + StackToString()); 469 | Console.WriteLine(" Line: " + line); 470 | Console.WriteLine(" File: " + filename); 471 | Console.WriteLine(" ToString: " + e.ToString()); 472 | Console.WriteLine("---"); 473 | 474 | return; 475 | } 476 | 477 | private static void Logger(string msg) 478 | { 479 | Console.WriteLine(msg); 480 | } 481 | } 482 | } 483 | -------------------------------------------------------------------------------- /src/Test.SqliteAsync/Test.SqliteAsync.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Test.SqliteAsync/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test.SqliteAsync/headshot.png -------------------------------------------------------------------------------- /src/Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net48;net6.0;net8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Always 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Test/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jchristn/DatabaseWrapper/acdb6408f387d17c1b096c49accd0970b0a1a786/src/Test/headshot.png --------------------------------------------------------------------------------