├── .config └── dotnet-tools.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── dotnet-core.yml ├── .gitignore ├── .paket ├── paket.bootstrapper.exe └── paket.targets ├── .travis.yml ├── .vs └── config │ └── applicationhost.config ├── CONTRIBUTING.md ├── Directory.Build.props ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── RELEASE_NOTES.md ├── Samples.sln ├── SqlClient.sln ├── SqlClient.userprefs ├── TestProjects.sln ├── Tests.sln ├── Types Cache.md ├── appveyor.yml ├── build.cmd ├── build.sh ├── build ├── build.fs ├── build.fsproj ├── fakeiisexpress.fs ├── fakexunithelper.fs └── paket.references ├── docs ├── content │ ├── GetDate.sql │ ├── SqlClientComparison.md │ ├── app.config │ ├── bulk load.fsx │ ├── comparison.fsx │ ├── configuration and Input.fsx │ ├── data modification.fsx │ ├── debugging.fsx │ ├── dynamic local db.fsx │ ├── faq.fsx │ ├── index.fsx │ ├── netcore.md │ ├── output.fsx │ ├── reference architecture.fsx │ ├── setup.fsx │ ├── sqlenumprovider.quickstart.fsx │ ├── transactions.fsx │ ├── unit-testing.fsx │ ├── user.config │ └── whatsnew.fsx ├── files │ └── img │ │ ├── AddRow.png │ │ ├── ConnStrByNameAppConfig.png │ │ ├── ConnStrByNameUserConfig.png │ │ ├── ConnStrByNameUserConfig2.png │ │ ├── DataRowTypedAccessors.png │ │ ├── dapper.png │ │ ├── error_in_query.png │ │ ├── logo.pdn │ │ ├── logo.png │ │ ├── sql_file_As_CommandText_1.png │ │ └── sql_file_As_CommandText_2.png └── tools │ ├── generate.fsx │ └── templates │ └── template.cshtml ├── fsc.props ├── global.json ├── netfx.props ├── nuget ├── SqlClient.nuspec └── publish.cmd ├── paket.dependencies ├── paket.lock ├── provision.sh ├── src ├── SqlClient.DesignTime │ ├── AssemblyInfo.fs │ ├── DesignTime.fs │ ├── DesignTimeConnectionString.fs │ ├── ProvidedTypesCache.fs │ ├── QuotationsFactory.fs │ ├── Scripts │ │ ├── ReverseLineOrderForNotex.fsx │ │ ├── Scratchpad.fsx │ │ └── XE.fsx │ ├── SingleFileChangeMonitor.fs │ ├── SingleRootTypeProvider.fs │ ├── SqlClient.DesignTime.fsproj │ ├── SqlClientExtensions.fs │ ├── SqlClientProvider.fs │ ├── SqlCommandProvider.fs │ ├── SqlEnumProvider.fs │ ├── SqlFileProvider.fs │ └── paket.references ├── SqlClient.Samples │ ├── WebApi.Controllers │ │ ├── App.config │ │ ├── DataAccess.fs │ │ ├── HomeController.fs │ │ ├── T-SQL │ │ │ └── Products.sql │ │ ├── WebApi.Controllers.fsproj │ │ └── paket.references │ ├── WebApi │ │ ├── Global.asax │ │ ├── Global.asax.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── Web.Debug.config │ │ ├── Web.Release.config │ │ ├── WebApi.csproj │ │ ├── paket.references │ │ └── web.config │ └── WpfDataBinding │ │ ├── App.config │ │ ├── MainWindow.xaml │ │ ├── Program.fs │ │ ├── WpfDataBinding.fsproj │ │ └── paket.references ├── SqlClient.TestProjects │ ├── Lib │ │ ├── App.config │ │ ├── Lib.fsproj │ │ ├── Library1.fs │ │ ├── Script.fsx │ │ └── paket.references │ ├── SqlClient.Tests.NET40 │ │ ├── Program.fs │ │ ├── SqlClient.Tests.NET40.fsproj │ │ ├── Uncomment.App.config │ │ └── paket.references │ └── SqlClient.Tests.NetCoreApp │ │ ├── Program.fs │ │ ├── SqlClient.Tests.NetCoreApp.fsproj │ │ └── paket.references └── SqlClient │ ├── AssemblyInfo.fs │ ├── Configuration.fs │ ├── DataTable.fs │ ├── DebugProvidedTypes.fs │ ├── DynamicRecord.fs │ ├── Extensions.fs │ ├── ISqlCommand.fs │ ├── Properties │ └── launchSettings.json │ ├── Runtime.fs │ ├── Shared.fs │ └── SqlClient.fsproj ├── tests ├── SqlClient.DesignTime.Tests │ ├── DesignTimeConnectionStringTests.fs │ ├── SqlClient.DesignTime.Tests.fsproj │ ├── app.config │ └── paket.references ├── SqlClient.SqlServerTypes.Tests │ ├── App.config │ ├── SpatialTypesTests.fs │ ├── SqlClient.SqlServerTypes.Tests.fsproj │ └── paket.references └── SqlClient.Tests │ ├── AdventureWorks2012_Data.zip │ ├── Assert.fs │ ├── ConfigurationTest.fs │ ├── ConnectionStrings.fs │ ├── CreateCommand.fs │ ├── DataTablesTests.fs │ ├── DynamicRecordTests.fs │ ├── FreeVarDoubleDeclTests.fs │ ├── MySqlFolder │ └── sampleCommand.sql │ ├── OptionalParamsTests.fs │ ├── ProgrammabilityTests.fs │ ├── ResultTypeTests.fs │ ├── Scripts │ ├── CreateCommand.fsx │ ├── SqlCommand.fsx │ └── SqlProgrammability.fsx │ ├── SpReturnValueTests.fs │ ├── SqlClient.Tests.fsproj │ ├── SqlEnumTests.fs │ ├── SynonymsTests.fs │ ├── TVPTests.fs │ ├── TempTableTests.fs │ ├── TransactionTests.fs │ ├── TypeProviderTest.fs │ ├── UnitsOfMeasure.fs │ ├── app.config │ ├── appWithInclude.config │ ├── connectionStrings.Azure.config │ ├── connectionStrings.config │ ├── extensions.sql │ ├── paket.references │ └── sampleCommand.sql └── tools └── xUnit ├── HTML.xslt ├── NUnitXml.xslt ├── license.txt ├── xunit.console.clr4.exe ├── xunit.console.clr4.exe.config ├── xunit.console.clr4.x86.exe ├── xunit.console.clr4.x86.exe.config ├── xunit.console.exe ├── xunit.console.exe.config ├── xunit.console.x86.exe ├── xunit.console.x86.exe.config ├── xunit.dll ├── xunit.dll.tdnet ├── xunit.extensions.dll ├── xunit.extensions.xml ├── xunit.gui.clr4.exe ├── xunit.gui.clr4.x86.exe ├── xunit.gui.exe ├── xunit.gui.x86.exe ├── xunit.runner.msbuild.dll ├── xunit.runner.tdnet.dll ├── xunit.runner.utility.dll ├── xunit.runner.utility.xml └── xunit.xml /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "paket": { 6 | "version": "9.0.2", 7 | "commands": [ 8 | "paket" 9 | ], 10 | "rollForward": false 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: bug_report 3 | about: Bug report 4 | title: One line summary of the bug 5 | labels: '' 6 | assignees: smoothdeveloper 7 | 8 | --- 9 | 10 | ### Issue Summary 11 | 12 | 13 | #### To Reproduce 14 | 15 | Possibly share SQL Schema, snippets of data, and how you call it in F#. 16 | 17 | Steps to reproduce the behavior: 18 | * ... 19 | * ... 20 | * ... 21 | * See error 22 | 23 | #### Error 24 | 25 | If applicable, screenshots, also give any technical information from your current investigation. 26 | 27 | ### Expected behavior 28 | 29 | Describe what should happen. 30 | 31 | ### What you can do 32 | 33 | * [x] I am willing to contribute a PR with a unit test showcasing the issue 34 | * [x] I am willing to test the bug fix before next release 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: One line summary of the idea 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### problem 11 | 12 | *A description of what the problem is, showing sample SQL and F# code and describing the issue, how it is currently worked around.* 13 | 14 | 15 | ```sql 16 | 17 | ``` 18 | 19 | ```fsharp 20 | 21 | ``` 22 | 23 | ### solution 24 | 25 | *Propose what the end result code for consumers of the library should look like, how it should be tested, documented.* 26 | 27 | ### more info 28 | 29 | List possible alternatives / choices for the feature request to help user understand. 30 | 31 | ### What you can do 32 | * [ ] I consider contributing the feature 33 | * [ ] I consider help in testing the feature 34 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-core.yml: -------------------------------------------------------------------------------- 1 | name: FSharp.Data.SqlClient 'Actions' CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Setup .NET Core 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: 8.0.100 20 | 21 | - name: Install SQL Server 22 | # reference @ https://github.com/Particular/install-sql-server-action 23 | uses: Particular/install-sql-server-action@v1.0.0 24 | with: 25 | connection-string-env-var: GITHUB_ACTION_SQL_SERVER_CONNECTION_STRING 26 | catalog: AdventureWorks2012 27 | extra-params: "" 28 | - name: Build 29 | env: 30 | FSHARP_DATA_SQLCLIENT_USE_SQLLOCALDB_FOR_TESTS: 1 31 | run: | 32 | '"C:/Program Files/Microsoft SQL Server/130/Tools/Binn/SqlLocalDB.exe" info' 33 | ./build.cmd 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nuget/*.nupkg 2 | packages 3 | docs/output 4 | temp 5 | .vs/ 6 | 7 | ################# 8 | ## Eclipse 9 | ################# 10 | 11 | *.pydevproject 12 | .project 13 | .metadata 14 | bin/ 15 | tmp/ 16 | *.tmp 17 | *.bak 18 | *.swp 19 | *~.nib 20 | local.properties 21 | .classpath 22 | .settings/ 23 | .loadpath 24 | 25 | # External tool builders 26 | .externalToolBuilders/ 27 | 28 | # Locally stored "Eclipse launch configurations" 29 | *.launch 30 | 31 | # CDT-specific 32 | .cproject 33 | 34 | # PDT-specific 35 | .buildpath 36 | 37 | 38 | ################# 39 | ## Visual Studio 40 | ################# 41 | 42 | ## Ignore Visual Studio temporary files, build results, and 43 | ## files generated by popular Visual Studio add-ons. 44 | 45 | # User-specific files 46 | *.suo 47 | *.user 48 | *.sln.docstates 49 | launchSettings.json 50 | # Build results 51 | 52 | [Dd]ebug/ 53 | [Rr]elease/ 54 | x64/ 55 | build/ 56 | [Bb]in/ 57 | [Oo]bj/ 58 | 59 | # MSTest test Results 60 | [Tt]est[Rr]esult*/ 61 | [Bb]uild[Ll]og.* 62 | 63 | *_i.c 64 | *_p.c 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.pch 69 | *.pdb 70 | *.pgc 71 | *.pgd 72 | *.rsp 73 | *.sbr 74 | *.tlb 75 | *.tli 76 | *.tlh 77 | *.tmp 78 | *.tmp_proj 79 | *.log 80 | *.vspscc 81 | *.vssscc 82 | .builds 83 | *.pidb 84 | *.log 85 | *.scc 86 | 87 | # Visual C++ cache files 88 | ipch/ 89 | *.aps 90 | *.ncb 91 | *.opensdf 92 | *.sdf 93 | *.cachefile 94 | 95 | # Visual Studio profiler 96 | *.psess 97 | *.vsp 98 | *.vspx 99 | 100 | # Guidance Automation Toolkit 101 | *.gpState 102 | 103 | # ReSharper is a .NET coding add-in 104 | _ReSharper*/ 105 | *.[Rr]e[Ss]harper 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | *.ncrunch* 115 | .*crunch*.local.xml 116 | _NCrunch_* 117 | 118 | # Installshield output folder 119 | [Ee]xpress/ 120 | 121 | # DocProject is a documentation generator add-in 122 | DocProject/buildhelp/ 123 | DocProject/Help/*.HxT 124 | DocProject/Help/*.HxC 125 | DocProject/Help/*.hhc 126 | DocProject/Help/*.hhk 127 | DocProject/Help/*.hhp 128 | DocProject/Help/Html2 129 | DocProject/Help/html 130 | 131 | # Click-Once directory 132 | publish/ 133 | 134 | # Publish Web Output 135 | *.Publish.xml 136 | *.pubxml 137 | 138 | # NuGet Packages Directory 139 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 140 | #packages/ 141 | 142 | # Windows Azure Build Output 143 | csx 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.[Pp]ublish.xml 158 | *.pfx 159 | *.publishsettings 160 | 161 | # RIA/Silverlight projects 162 | Generated_Code/ 163 | 164 | # Backup & report files from converting an old project file to a newer 165 | # Visual Studio version. Backup files are not needed, because we have git ;-) 166 | _UpgradeReport_Files/ 167 | Backup*/ 168 | UpgradeLog*.XML 169 | UpgradeLog*.htm 170 | 171 | # SQL Server files 172 | App_Data/*.mdf 173 | App_Data/*.ldf 174 | 175 | ############# 176 | ## Windows detritus 177 | ############# 178 | 179 | # Windows image file caches 180 | Thumbs.db 181 | ehthumbs.db 182 | 183 | # Folder config file 184 | Desktop.ini 185 | 186 | # Recycle Bin used on file shares 187 | $RECYCLE.BIN/ 188 | 189 | # Mac crap 190 | .DS_Store 191 | 192 | 193 | ############# 194 | ## Python 195 | ############# 196 | 197 | *.py[co] 198 | 199 | # Packages 200 | *.egg 201 | *.egg-info 202 | dist/ 203 | build/ 204 | eggs/ 205 | parts/ 206 | var/ 207 | sdist/ 208 | develop-eggs/ 209 | .installed.cfg 210 | 211 | # Installer logs 212 | pip-log.txt 213 | 214 | # Unit test / coverage reports 215 | .coverage 216 | .tox 217 | 218 | #Translations 219 | *.mo 220 | 221 | #Mr Developer 222 | .mr.developer.cfg 223 | /packages 224 | /.nuget 225 | .vagrant/ 226 | vagrantfile 227 | *.userprefs 228 | /sqlclientmonosample 229 | .fake/ 230 | /_NCrunch_SqlProgrammabilityProvider/StoredText 231 | .idea 232 | paket-files 233 | paket.exe 234 | Paket.Restore.targets 235 | .paket 236 | /docs/output 237 | docs/output/**/*.* 238 | *.orig 239 | -------------------------------------------------------------------------------- /.paket/paket.bootstrapper.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/.paket/paket.bootstrapper.exe -------------------------------------------------------------------------------- /.paket/paket.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | $(MSBuildThisFileDirectory) 8 | $(MSBuildThisFileDirectory)..\ 9 | $(PaketRootPath)paket.lock 10 | $(PaketRootPath)paket-files\paket.restore.cached 11 | /Library/Frameworks/Mono.framework/Commands/mono 12 | mono 13 | 14 | 15 | 16 | 17 | $(PaketRootPath)paket.exe 18 | $(PaketToolsPath)paket.exe 19 | "$(PaketExePath)" 20 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" 21 | 22 | 23 | 24 | 25 | 26 | $(MSBuildProjectFullPath).paket.references 27 | 28 | 29 | 30 | 31 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references 32 | 33 | 34 | 35 | 36 | $(MSBuildProjectDirectory)\paket.references 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | $(PaketCommand) restore --references-file "$(PaketReferences)" 49 | 50 | RestorePackages; $(BuildDependsOn); 51 | 52 | 53 | 54 | true 55 | 56 | 57 | 58 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) 59 | $([System.IO.File]::ReadAllText('$(PaketLockFilePath)')) 60 | true 61 | false 62 | true 63 | 64 | 65 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | 3 | mono: 4 | - latest 5 | 6 | addons: 7 | apt: 8 | packages: 9 | - libunwind8 10 | 11 | script: 12 | - ./build.sh BuildTestProjects 13 | 14 | install: 15 | - export FrameworkPathOverride=$(dirname $(which mono))/../lib/mono/4.5/ 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | Contributions to this repository are welcome, you can engage with users and contributors [on Gitter https://gitter.im/fsprojects/FSharp.Data.SqlClient](https://gitter.im/fsprojects/FSharp.Data.SqlClient) chat room. 4 | 5 | ## Code and documentation contributions: 6 | 7 | There is very low bar for submitting a PR for review and discussion, changes to code that will get merged will generally requires a bit of back and forth beyond simplest fixes. 8 | 9 | ### Contributing to the docs 10 | 11 | The best way is to pull the repository and build it, then you can use those FAKE build targets (run a single target with `build.cmd TargetName -st` if you don't want to start from a clean build): 12 | 13 | * **GenerateDocs** : Will run FSharp.Formatting over the ./docs/contents folder. 14 | * **ServeDocs** : Will run IIS Express to serve the docs, and then show the home URL with your default browser. 15 | 16 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | $(WarningsNotAsErrors);44; 7 | latest 8 | 9 | 10 | Release 11 | AnyCPU 12 | true 13 | true 14 | 22 | $(WarningsNotAsErrors);NU1504;NU1701;NU1902;NU1903;NU1904 23 | 24 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Please provide a succinct description of your issue. 5 | 6 | ### Repro steps 7 | 8 | Please provide the steps required to reproduce the problem 9 | 10 | 1. Step A 11 | 12 | 2. Step B 13 | 14 | ### Expected behavior 15 | 16 | Please provide a description of the behaviour you expect. 17 | 18 | ### Actual behavior 19 | 20 | Please provide a description of the actual behaviour you observe. 21 | 22 | ### Known workarounds 23 | 24 | Please provide a description of any known workarounds. 25 | 26 | ### Related information 27 | 28 | * Operating system 29 | * Branch 30 | * Database versions and sample databases being used 31 | * .NET Runtime, CoreCLR or Mono Version 32 | * Editing Tools (e.g. Visual Studio Version) 33 | * Lins to F# RFCs or entries on http://fslang.uservoice.com 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FSharp.Data.SqlClient - Type providers for Microsoft SQL Server 2 | 3 | This library exposes SQL Server Database objects in a type safe manner to F# code, by the mean of [Type Providers](https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/) 4 | 5 | You can reference it in F# Interactive that ships with Visual Studio 6 | ```fsharp 7 | #r "nuget: FSharp.Data.SqlClient" 8 | open FSharp.Data 9 | open FSharp.Data.SqlClient 10 | let [] connectionString = "Server=.;Database=AdventureWorks2012;Trusted_Connection=True;" 11 | type MyCommand = SqlCommandProvider<""" 12 | select 13 | data.a 14 | from 15 | (select 1 a union all select 2 union all select 3) data 16 | where 17 | data.a > @data 18 | """, connectionString>;; 19 | 20 | (new MyCommand(connectionString)).Execute(data=1) 21 | |> Seq.toArray 22 | |> printfn "%A" 23 | ``` 24 | 25 | `dotnet fsi` is not supported yet. 26 | 27 | ## Quick Links 28 | * [Documentation](http://fsprojects.github.io/FSharp.Data.SqlClient/) 29 | * [Release Notes](RELEASE_NOTES.md) 30 | * [Contribution Guide Lines](CONTRIBUTING.md) 31 | * [Gitter Chat Room](https://gitter.im/fsprojects/FSharp.Data.SqlClient) 32 | * [FSharp.Data.SqlClient on nuget.org](https://www.nuget.org/packages/FSharp.Data.SqlClient/) 33 | ## Type Providers 34 | 35 | ### SqlCommandProvider 36 | 37 | Provides statically typed access to the parameters and result set of T-SQL command in idiomatic F# way (*). 38 | 39 | ```fsharp 40 | open FSharp.Data 41 | 42 | [] 43 | let connectionString = "Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 44 | 45 | // The query below retrieves top 3 sales representatives from North American region with YTD sales of more than one million. 46 | 47 | do 48 | use cmd = new SqlCommandProvider<" 49 | SELECT TOP(@topN) FirstName, LastName, SalesYTD 50 | FROM Sales.vSalesPerson 51 | WHERE CountryRegionName = @regionName AND SalesYTD > @salesMoreThan 52 | ORDER BY SalesYTD 53 | " , connectionString>(connectionString) 54 | 55 | cmd.Execute(topN = 3L, regionName = "United States", salesMoreThan = 1000000M) |> printfn "%A" 56 | ``` 57 | output 58 | ```fsharp 59 | seq 60 | [("Pamela", "Ansman-Wolfe", 1352577.1325M); 61 | ("David", "Campbell", 1573012.9383M); 62 | ("Tete", "Mensa-Annan", 1576562.1966M)] 63 | ``` 64 | 65 | ### SqlProgrammabilityProvider 66 | 67 | Exposes Tables, Stored Procedures, User-Defined Types and User-Defined Functions in F# code. 68 | 69 | ```fsharp 70 | type AdventureWorks = SqlProgrammabilityProvider 71 | do 72 | use cmd = new AdventureWorks.dbo.uspGetWhereUsedProductID(connectionString) 73 | for x in cmd.Execute( StartProductID = 1, CheckDate = System.DateTime(2013,1,1)) do 74 | //check for nulls 75 | match x.ProductAssemblyID, x.StandardCost, x.TotalQuantity with 76 | | Some prodAsmId, Some cost, Some qty -> 77 | printfn "ProductAssemblyID: %i, StandardCost: %M, TotalQuantity: %M" prodAsmId cost qty 78 | | _ -> () 79 | ``` 80 | output 81 | ```fsharp 82 | ProductAssemblyID: 749, StandardCost: 2171.2942, TotalQuantity: 1.00 83 | ProductAssemblyID: 750, StandardCost: 2171.2942, TotalQuantity: 1.00 84 | ProductAssemblyID: 751, StandardCost: 2171.2942, TotalQuantity: 1.00 85 | ``` 86 | 87 | ### SqlEnumProvider 88 | 89 | Let's say we need to retrieve number of orders shipped by a certain shipping method since specific date. 90 | 91 | ```fsharp 92 | //by convention: first column is Name, second is Value 93 | type ShipMethod = SqlEnumProvider<" 94 | SELECT Name, ShipMethodID FROM Purchasing.ShipMethod ORDER BY ShipMethodID", connectionString> 95 | 96 | //Combine with SqlCommandProvider 97 | do 98 | use cmd = new SqlCommandProvider<" 99 | SELECT COUNT(*) 100 | FROM Purchasing.PurchaseOrderHeader 101 | WHERE ShipDate > @shippedLaterThan AND ShipMethodID = @shipMethodId 102 | ", connectionString, SingleRow = true>(connectionString) 103 | //overnight orders shipped since Jan 1, 2008 104 | cmd.Execute( System.DateTime( 2008, 1, 1), ShipMethod.``OVERNIGHT J-FAST``) |> printfn "%A" 105 | ``` 106 | output 107 | ```fsharp 108 | Some (Some 1085) 109 | ``` 110 | 111 | ### SqlFileProvider 112 | 113 | ```fsharp 114 | type SampleCommand = SqlFile<"sampleCommand.sql"> 115 | type SampleCommandRelative = SqlFile<"sampleCommand.sql", "MySqlFolder"> 116 | 117 | use cmd1 = new SqlCommandProvider() 118 | use cmd2 = new SqlCommandProvider() 119 | ``` 120 | 121 | More information can be found in the [documentation](http://fsprojects.github.io/FSharp.Data.SqlClient/). 122 | 123 | ## Build Status 124 | 125 | | Windows | Linux | NuGet | 126 | |:-------:|:-----:|:-----:| 127 | |[![Build status (Windows Server 2012, AppVeyor)](https://ci.appveyor.com/api/projects/status/gxou8oe4lt5adxbq)](https://ci.appveyor.com/project/fsgit/fsharp-data-sqlclient)|[![Build Status](https://travis-ci.org/fsprojects/FSharp.Data.SqlClient.svg?branch=master)](https://travis-ci.org/fsprojects/FSharp.Data.SqlClient)|[![NuGet Status](http://img.shields.io/nuget/v/FSharp.Data.SqlClient.svg?style=flat)](https://www.nuget.org/packages/FSharp.Data.SqlClient/)| 128 | 129 | ### Maintainers 130 | 131 | - [@smoothdeveloper](https://github.com/smoothdeveloper) 132 | 133 | The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) - F# Community Project Incubation Space (repo management) 134 | 135 | Thanks Jetbrains for their open source license program and providing their tool. 136 | -------------------------------------------------------------------------------- /Samples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{3F96B803-B577-49EF-80BE-9185D114135F}" 7 | ProjectSection(SolutionItems) = preProject 8 | paket.dependencies = paket.dependencies 9 | EndProjectSection 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApi", "src\SqlClient.Samples\WebApi\WebApi.csproj", "{EB1F8003-352C-448B-81AC-9823BEB1B325}" 12 | EndProject 13 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WebApi.Controllers", "src\SqlClient.Samples\WebApi.Controllers\WebApi.Controllers.fsproj", "{92308B2E-43B4-4C4C-9446-87D02C4E455D}" 14 | EndProject 15 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WpfDataBinding", "src\SqlClient.Samples\WpfDataBinding\WpfDataBinding.fsproj", "{3BA10AE4-4E31-4588-B77F-AB971DB27219}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {EB1F8003-352C-448B-81AC-9823BEB1B325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {EB1F8003-352C-448B-81AC-9823BEB1B325}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {EB1F8003-352C-448B-81AC-9823BEB1B325}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {EB1F8003-352C-448B-81AC-9823BEB1B325}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {92308B2E-43B4-4C4C-9446-87D02C4E455D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {92308B2E-43B4-4C4C-9446-87D02C4E455D}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {92308B2E-43B4-4C4C-9446-87D02C4E455D}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {92308B2E-43B4-4C4C-9446-87D02C4E455D}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {3BA10AE4-4E31-4588-B77F-AB971DB27219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {3BA10AE4-4E31-4588-B77F-AB971DB27219}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {3BA10AE4-4E31-4588-B77F-AB971DB27219}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {3BA10AE4-4E31-4588-B77F-AB971DB27219}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /SqlClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34309.116 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{FD7933BD-2A90-49EB-A4B2-95F9D3076BBD}" 7 | ProjectSection(SolutionItems) = preProject 8 | paket.dependencies = paket.dependencies 9 | EndProjectSection 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{7ECDF2A7-A71C-43B5-AFF2-64468098B7B6}" 12 | ProjectSection(SolutionItems) = preProject 13 | nuget\SqlClient.nuspec = nuget\SqlClient.nuspec 14 | EndProjectSection 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9E58B00A-A993-4542-B40F-C58AC1A9AA4D}" 17 | ProjectSection(SolutionItems) = preProject 18 | build.cmd = build.cmd 19 | build.fsx = build.fsx 20 | Directory.Build.props = Directory.Build.props 21 | fsc.props = fsc.props 22 | LICENSE.md = LICENSE.md 23 | netfx.props = netfx.props 24 | README.md = README.md 25 | RELEASE_NOTES.md = RELEASE_NOTES.md 26 | EndProjectSection 27 | EndProject 28 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{61AC061E-5824-41B7-8E09-8D3A73D564E5}" 29 | EndProject 30 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{4B60BF24-D078-4950-A994-A633FBC272EB}" 31 | ProjectSection(SolutionItems) = preProject 32 | docs\content\comparison.fsx = docs\content\comparison.fsx 33 | docs\content\configuration and input.fsx = docs\content\configuration and input.fsx 34 | docs\content\data modification.fsx = docs\content\data modification.fsx 35 | docs\content\debugging.fsx = docs\content\debugging.fsx 36 | docs\content\faq.fsx = docs\content\faq.fsx 37 | docs\content\index.fsx = docs\content\index.fsx 38 | docs\content\netcore.md = docs\content\netcore.md 39 | docs\content\output.fsx = docs\content\output.fsx 40 | docs\content\setup.fsx = docs\content\setup.fsx 41 | docs\content\SqlClientComparison.md = docs\content\SqlClientComparison.md 42 | docs\content\sqlenumprovider.quickstart.fsx = docs\content\sqlenumprovider.quickstart.fsx 43 | docs\content\transactions.fsx = docs\content\transactions.fsx 44 | docs\content\unit-testing.fsx = docs\content\unit-testing.fsx 45 | docs\content\whatsnew.fsx = docs\content\whatsnew.fsx 46 | EndProjectSection 47 | EndProject 48 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{573DBBFB-0F97-4327-8614-6A4151CD70BF}" 49 | ProjectSection(SolutionItems) = preProject 50 | docs\tools\generate.fsx = docs\tools\generate.fsx 51 | EndProjectSection 52 | EndProject 53 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "templates", "templates", "{CB79269B-025B-4D6A-AF84-0AD821F6A602}" 54 | ProjectSection(SolutionItems) = preProject 55 | docs\tools\templates\template.cshtml = docs\tools\templates\template.cshtml 56 | EndProjectSection 57 | EndProject 58 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient.DesignTime", "src\SqlClient.DesignTime\SqlClient.DesignTime.fsproj", "{8974CE2E-79B4-4887-859A-B853C2624138}" 59 | EndProject 60 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient", "src\SqlClient\SqlClient.fsproj", "{30BA2514-534A-42EA-A0E7-46DF9FDCA954}" 61 | ProjectSection(ProjectDependencies) = postProject 62 | {8974CE2E-79B4-4887-859A-B853C2624138} = {8974CE2E-79B4-4887-859A-B853C2624138} 63 | EndProjectSection 64 | EndProject 65 | Global 66 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 67 | Debug|Any CPU = Debug|Any CPU 68 | Release|Any CPU = Release|Any CPU 69 | EndGlobalSection 70 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 71 | {8974CE2E-79B4-4887-859A-B853C2624138}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 72 | {8974CE2E-79B4-4887-859A-B853C2624138}.Debug|Any CPU.Build.0 = Debug|Any CPU 73 | {8974CE2E-79B4-4887-859A-B853C2624138}.Release|Any CPU.ActiveCfg = Release|Any CPU 74 | {8974CE2E-79B4-4887-859A-B853C2624138}.Release|Any CPU.Build.0 = Release|Any CPU 75 | {30BA2514-534A-42EA-A0E7-46DF9FDCA954}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 76 | {30BA2514-534A-42EA-A0E7-46DF9FDCA954}.Debug|Any CPU.Build.0 = Debug|Any CPU 77 | {30BA2514-534A-42EA-A0E7-46DF9FDCA954}.Release|Any CPU.ActiveCfg = Release|Any CPU 78 | {30BA2514-534A-42EA-A0E7-46DF9FDCA954}.Release|Any CPU.Build.0 = Release|Any CPU 79 | EndGlobalSection 80 | GlobalSection(SolutionProperties) = preSolution 81 | HideSolutionNode = FALSE 82 | EndGlobalSection 83 | GlobalSection(NestedProjects) = preSolution 84 | {4B60BF24-D078-4950-A994-A633FBC272EB} = {61AC061E-5824-41B7-8E09-8D3A73D564E5} 85 | {573DBBFB-0F97-4327-8614-6A4151CD70BF} = {61AC061E-5824-41B7-8E09-8D3A73D564E5} 86 | {CB79269B-025B-4D6A-AF84-0AD821F6A602} = {573DBBFB-0F97-4327-8614-6A4151CD70BF} 87 | EndGlobalSection 88 | GlobalSection(ExtensibilityGlobals) = postSolution 89 | SolutionGuid = {82096CC6-31F2-47A5-8D46-E41C63B4DB58} 90 | EndGlobalSection 91 | EndGlobal 92 | -------------------------------------------------------------------------------- /SqlClient.userprefs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TestProjects.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2041 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{E35ED000-5A6C-49E1-82CF-55CB8C16C2AB}" 7 | ProjectSection(SolutionItems) = preProject 8 | paket.dependencies = paket.dependencies 9 | EndProjectSection 10 | EndProject 11 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Lib", "src\SqlClient.TestProjects\Lib\Lib.fsproj", "{5DD83156-9416-439F-983A-8ED1A0F1F822}" 12 | EndProject 13 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient.Tests.NET40", "src\SqlClient.TestProjects\SqlClient.Tests.NET40\SqlClient.Tests.NET40.fsproj", "{34413B8D-884B-4F4D-B6DC-637FAE859738}" 14 | EndProject 15 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient.Tests.NetCoreApp", "src\SqlClient.TestProjects\SqlClient.Tests.NetCoreApp\SqlClient.Tests.NetCoreApp.fsproj", "{251C7367-0556-4831-BE20-CAF29989B833}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {5DD83156-9416-439F-983A-8ED1A0F1F822}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {5DD83156-9416-439F-983A-8ED1A0F1F822}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {5DD83156-9416-439F-983A-8ED1A0F1F822}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {5DD83156-9416-439F-983A-8ED1A0F1F822}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {34413B8D-884B-4F4D-B6DC-637FAE859738}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {34413B8D-884B-4F4D-B6DC-637FAE859738}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {34413B8D-884B-4F4D-B6DC-637FAE859738}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {34413B8D-884B-4F4D-B6DC-637FAE859738}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {251C7367-0556-4831-BE20-CAF29989B833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {251C7367-0556-4831-BE20-CAF29989B833}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {251C7367-0556-4831-BE20-CAF29989B833}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {251C7367-0556-4831-BE20-CAF29989B833}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | GlobalSection(ExtensibilityGlobals) = postSolution 40 | SolutionGuid = {BB177D8C-41D5-430D-94E8-485567A72F92} 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /Tests.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34310.174 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{E35ED000-5A6C-49E1-82CF-55CB8C16C2AB}" 7 | ProjectSection(SolutionItems) = preProject 8 | paket.dependencies = paket.dependencies 9 | paket.lock = paket.lock 10 | EndProjectSection 11 | EndProject 12 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient.Tests", "tests\SqlClient.Tests\SqlClient.Tests.fsproj", "{36665EFF-56A2-46C2-852D-6D26DF492D79}" 13 | EndProject 14 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient.DesignTime.Tests", "tests\SqlClient.DesignTime.Tests\SqlClient.DesignTime.Tests.fsproj", "{167862B2-5588-4DF8-A7D3-05C1A5A835CA}" 15 | EndProject 16 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SqlClient.SqlServerTypes.Tests", "tests\SqlClient.SqlServerTypes.Tests\SqlClient.SqlServerTypes.Tests.fsproj", "{CF3D9433-B20A-4E5A-9401-F6518CBAD34E}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{0005CBDB-E976-46EE-89A0-CEE3F25A9365}" 19 | ProjectSection(SolutionItems) = preProject 20 | Directory.Build.props = Directory.Build.props 21 | fsc.props = fsc.props 22 | netfx.props = netfx.props 23 | EndProjectSection 24 | EndProject 25 | Global 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|Any CPU = Debug|Any CPU 28 | Release|Any CPU = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 31 | {36665EFF-56A2-46C2-852D-6D26DF492D79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {36665EFF-56A2-46C2-852D-6D26DF492D79}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {36665EFF-56A2-46C2-852D-6D26DF492D79}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {36665EFF-56A2-46C2-852D-6D26DF492D79}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {167862B2-5588-4DF8-A7D3-05C1A5A835CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {167862B2-5588-4DF8-A7D3-05C1A5A835CA}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {167862B2-5588-4DF8-A7D3-05C1A5A835CA}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {167862B2-5588-4DF8-A7D3-05C1A5A835CA}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {CF3D9433-B20A-4E5A-9401-F6518CBAD34E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {CF3D9433-B20A-4E5A-9401-F6518CBAD34E}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {CF3D9433-B20A-4E5A-9401-F6518CBAD34E}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {CF3D9433-B20A-4E5A-9401-F6518CBAD34E}.Release|Any CPU.Build.0 = Release|Any CPU 43 | EndGlobalSection 44 | GlobalSection(SolutionProperties) = preSolution 45 | HideSolutionNode = FALSE 46 | EndGlobalSection 47 | GlobalSection(ExtensibilityGlobals) = postSolution 48 | SolutionGuid = {BB177D8C-41D5-430D-94E8-485567A72F92} 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /Types Cache.md: -------------------------------------------------------------------------------- 1 | Generated erased types cache 2 | ============================== 3 | 4 | Considerations 5 | ----------- 6 | Current state 7 | ----------- 8 | Problems 9 | ----------- 10 | Proprosed solution 11 | ----------- 12 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | init: 2 | - git config --global core.autocrlf input 3 | - net start MSSQL$SQL2019 4 | image: Visual Studio 2022 5 | build_script: 6 | - cmd: build.cmd --target GenerateDocs 7 | test: off 8 | version: 0.0.1.{build} 9 | artifacts: 10 | - path: bin 11 | name: bin -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | dotnet tool restore 4 | if errorlevel 1 ( 5 | exit /b %errorlevel% 6 | ) 7 | 8 | dotnet paket restore 9 | if errorlevel 1 ( 10 | exit /b %errorlevel% 11 | ) 12 | 13 | dotnet run --project build %* -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | cd `dirname $0` 7 | 8 | dotnet tool restore 9 | dotnet paket restore 10 | dotnet run --project build "$@" 11 | -------------------------------------------------------------------------------- /build/build.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /build/fakeiisexpress.fs: -------------------------------------------------------------------------------- 1 | // https://github.com/fsharp/FAKE/blob/e1378887c41c37d425e134f83424424b76781228/src/legacy/Fake.IIS/IISExpress.fs 2 | // added HostStaticWebsite 3 | module fakeiisexpress 4 | 5 | open Fake.Core 6 | open System.Diagnostics 7 | open System 8 | open System.IO 9 | open System.Xml.Linq 10 | 11 | /// Options for using IISExpress 12 | [] 13 | type IISExpressOptions = 14 | { ToolPath : string } 15 | 16 | /// IISExpress default parameters - tries to locate the iisexpress.exe 17 | [] 18 | let IISExpressDefaults = 19 | { ToolPath = 20 | let root = 21 | if Environment.Is64BitOperatingSystem then 22 | Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) 23 | else Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) 24 | 25 | Path.Combine(root, "IIS Express", "iisexpress.exe") } 26 | 27 | /// Create a IISExpress config file from a given template 28 | [] 29 | let createConfigFile (name, siteId : int, templateFileName, path, hostName, port : int) = 30 | let xname s = XName.Get(s) 31 | let uniqueConfigFile = Path.Combine(Path.GetTempPath(), "iisexpress-" + Guid.NewGuid().ToString() + ".config") 32 | use template = File.OpenRead(templateFileName) 33 | let xml = XDocument.Load(template) 34 | let sitesElement = xml.Root.Element(xname "system.applicationHost").Element(xname "sites") 35 | let appElement = 36 | XElement 37 | (xname "site", XAttribute(xname "name", name), XAttribute(xname "id", siteId.ToString()), 38 | XAttribute(xname "serverAutoStart", "true"), 39 | 40 | XElement 41 | (xname "application", XAttribute(xname "path", "/"), 42 | 43 | XElement 44 | (xname "virtualDirectory", XAttribute(xname "path", "/"), XAttribute(xname "physicalPath", DirectoryInfo(path).FullName))), 45 | 46 | XElement 47 | (xname "bindings", 48 | 49 | XElement 50 | (xname "binding", XAttribute(xname "protocol", "http"), 51 | XAttribute(xname "bindingInformation", "*:" + port.ToString() + ":" + hostName)), 52 | 53 | XElement 54 | (xname "binding", XAttribute(xname "protocol", "http"), 55 | XAttribute(xname "bindingInformation", "*:" + port.ToString() + ":*")))) 56 | sitesElement.Add(appElement) 57 | xml.Save(uniqueConfigFile) 58 | uniqueConfigFile 59 | 60 | #nowarn "44" // obsolete api 61 | /// This task starts the given site in IISExpress with the given ConfigFile. 62 | /// ## Parameters 63 | /// 64 | /// - `setParams` - Function used to overwrite the default parameters. 65 | /// - `configFileName` - The file name of the IISExpress configfile. 66 | /// - `siteId` - The id (in the config file) of the website to run. 67 | /// 68 | /// ## Sample 69 | /// 70 | /// HostWebsite (fun p -> { p with ToolPath = "iisexpress.exe" }) "configfile.config" 1 71 | [] 72 | let HostWebsite setParams configFileName siteId = 73 | let parameters = setParams IISExpressDefaults 74 | 75 | use __ = Trace.traceTask "StartWebSite" configFileName 76 | let args = sprintf "/config:\"%s\" /siteid:%d" configFileName siteId 77 | Trace.tracefn "Starting WebSite with %s %s" parameters.ToolPath args 78 | 79 | let proc = 80 | ProcessStartInfo(FileName = parameters.ToolPath, Arguments = args, UseShellExecute = false) 81 | |> Process.Start 82 | 83 | proc 84 | 85 | let HostStaticWebsite setParams folder = 86 | // https://blogs.msdn.microsoft.com/rido/2015/09/30/serving-static-content-with-iisexpress/ 87 | let parameters = setParams IISExpressDefaults 88 | 89 | use __ = Trace.traceTask "StartWebSite" folder 90 | let args = sprintf @"/path:""%s\""" folder 91 | Trace.tracefn "Starting WebSite with %s %s" parameters.ToolPath args 92 | 93 | let proc = 94 | ProcessStartInfo(FileName = parameters.ToolPath, Arguments = args, UseShellExecute = false) 95 | |> Process.Start 96 | 97 | proc 98 | 99 | /// Opens the given url in the browser 100 | [] 101 | let OpenUrlInBrowser url = Process.Start(url:string) |> ignore 102 | 103 | /// Opens the given website in the browser 104 | [] 105 | let OpenWebsiteInBrowser hostName port = sprintf "http://%s:%d/" hostName port |> OpenUrlInBrowser -------------------------------------------------------------------------------- /build/paket.references: -------------------------------------------------------------------------------- 1 | group Build 2 | 3 | Fun.Build 4 | Fake.Core.Process 5 | Fake.Core.ReleaseNotes 6 | Fake.Core.Target 7 | Fake.Core.Trace 8 | Fake.DotNet.AssemblyInfoFile 9 | Fake.DotNet.Cli 10 | Fake.DotNet.MSBuild 11 | Fake.DotNet.NuGet 12 | Fake.DotNet.Testing.XUnit2 13 | 14 | Fake.Tools.Git 15 | FSharp.Core 16 | FSharp.Formatting 17 | NuGet.CommandLine 18 | System.Data.SqlClient 19 | System.Configuration.ConfigurationManager -------------------------------------------------------------------------------- /docs/content/GetDate.sql: -------------------------------------------------------------------------------- 1 | SELECT GETDATE() AS Now -------------------------------------------------------------------------------- /docs/content/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/content/bulk load.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r @"..\..\bin\net462\FSharp.Data.SqlClient.dll" 3 | #r "System.Transactions" 4 | open FSharp.Data 5 | open System 6 | 7 | [] 8 | let connectionString = @"Data Source=.;Initial Catalog=AdventureWorks2014;Integrated Security=True;TrustServerCertificate=true" 9 | 10 | (** 11 | 12 | Bulk Load 13 | =================== 14 | 15 | *) 16 | -------------------------------------------------------------------------------- /docs/content/debugging.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r @"..\..\bin\net462\FSharp.Data.SqlClient.dll" 3 | #r "System.Transactions" 4 | open FSharp.Data 5 | open System 6 | 7 | [] 8 | let connectionString = @"Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 9 | 10 | (** 11 | 12 | Debugging 13 | =================== 14 | 15 | Following FSharp.Data.SqlClient specific techniques can be used to diagnose various issues. 16 | 17 | ToTraceString 18 | ------------------------------------- 19 | Call ToTraceString to get text representation of sql statement that will be executed in Sql Server 20 | 21 | *) 22 | 23 | let cmd = new SqlCommandProvider<" 24 | SELECT TOP(@topN) FirstName, LastName, SalesYTD 25 | FROM Sales.vSalesPerson 26 | WHERE CountryRegionName = @regionName AND SalesYTD > @salesMoreThan 27 | ORDER BY SalesYTD 28 | " , connectionString>(connectionString) 29 | 30 | cmd.ToTraceString(topN = 3L, regionName = "United States", salesMoreThan = 1000000M) 31 | |> printfn "Sql: %s" 32 | 33 | (** 34 | 35 | Direct access to underlying SqlCommand instance. 36 | ------------------------------------- 37 | If you feel that getting your hands on underlying ADO.NET SqlCommand can help to address a problem that can be done. 38 | Expect to see a warning because this is not intended for public use and subject for change. 39 | Avoid tempering state of this SqlCommand instance otherwise all bets are off. 40 | *) 41 | 42 | let adonetCmd = (cmd :> ISqlCommand).Raw 43 | 44 | [ for p in adonetCmd.Parameters -> p.ParameterName, p.SqlDbType ] 45 | |> printfn "Inferred parameters: %A" 46 | 47 | (** 48 | 49 | Result set runtime verification. 50 | ------------------------------------- 51 | While enjoying all benefits of static types at design time one can easily end up in a situation 52 | when runtime Sql Server database schema is different from compile time. 53 | Up until now this resulted in confusion runtime exception: `InvalidCastException("Specified cast is not valid.")`. 54 | 55 | To improve diagnostics without hurting performance a new global singleton configuration object is introduced. 56 | To access `Configuration` type open up `FSharp.Data.SqlClient` namespace. 57 | *) 58 | 59 | open FSharp.Data.SqlClient 60 | assert(Configuration.Current.ResultsetRuntimeVerification = false) 61 | 62 | (** 63 | So far it has only one property `ResultsetRuntimeVerification` which set to false by default. 64 | Set it to true to see more descriptive error like: 65 | 66 | `InvalidOperationException(Expected column [Total] of type "System.Int32" at position 1 (0-based indexing) 67 | but received column [Now] of type "System.DateTime")`. 68 | *) 69 | 70 | Configuration.Current <- { Configuration.Current with ResultsetRuntimeVerification = true } 71 | 72 | (** 73 | Other debugging/instrumentation tools to consider: 74 | ------------------------------------- 75 | 76 | - [Sql Profiler](https://msdn.microsoft.com/en-us/library/ms181091.aspx) 77 | - [ADO.NET tracing](https://msdn.microsoft.com/en-us/library/cc765421.aspx) 78 | - [Dynamic views](https://azure.microsoft.com/en-us/documentation/articles/sql-database-monitoring-with-dmvs/) 79 | - [Query store](https://azure.microsoft.com/en-us/blog/query-store-a-flight-data-recorder-for-your-database/) 80 | 81 | *) 82 | -------------------------------------------------------------------------------- /docs/content/faq.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r @"..\..\bin\net462\FSharp.Data.SqlClient.dll" 3 | #r "System.Transactions" 4 | open FSharp.Data 5 | 6 | [] 7 | let connectionString = @"Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 8 | 9 | (** 10 | FAQ 11 | =================== 12 | ### 1. How do I specify default value for a parameter? 13 | 14 | `SqlCommandProvider` generates parameters for all unbound T-SQL script variables. 15 | By definition those variables don't have default value. 16 | One workaround is to assume NULL as default value (see next item). 17 | The other option is to have default value logic in application code. 18 | 19 | If you feel strongly about having default parameter values defined in T-SQL 20 | consider wrapping it into stored procedure or function. Both accept default values for parameters. 21 | `SqlProgrammabilityProvider` supports this scenario by mapping it to .NET method parameters with default values. 22 | 23 | ### 2. How do I pass NULL as parameter value? 24 | 25 | By default SqlCommandProvider treat all parameters as mandatory. 26 | *) 27 | 28 | let echoOnly = 29 | new SqlCommandProvider<"SELECT ISNULL(@x, 42)", connectionString, SingleRow = true>(connectionString) 30 | echoOnly.Execute( x = (* must pass int value here *) 1) 31 | 32 | (** 33 | There is no way to pass NULL as value for parameter `@x` although the query knows how to handle it. 34 | 35 | To resolve the issue specify `AllParametersOptional = true` as static parameter to type provider. 36 | It makes all parameters of type `option<_>`. 37 | 38 |
39 | 40 | **Note** This is not same as F# optional parameters** but mimics them closely. 41 | Unfortunately type providers in general restricted to emit .NET 1.1 types only. 42 | No generics, no F# specific types/annotations which includes optional parameters. 43 | 44 |

45 | 46 | *) 47 | 48 | let echoOr42 = 49 | new SqlCommandProvider<" 50 | SELECT ISNULL(@x, 42) 51 | ", connectionString, SingleRow = true, AllParametersOptional = true>(connectionString) 52 | 53 | // Pass parameter value. Specifying Some constructor is mandatrory. 54 | echoOr42.Execute( Some 1) 55 | 56 | // Pass NULL 57 | echoOr42.Execute( x = None) 58 | 59 | (** 60 | ### 3. How do I do dynamic filter? 61 | 62 | Dynamic filters is when your T-SQL command accepts multiple input arguments and is supposed 63 | to determine which columns to filter, if at all, based on that input. 64 | 65 | Following command allows to filter dynamically information on sales people based on country and minimal sales amount. 66 | *) 67 | 68 | (** 69 | ### 4. Why do I get compile time error " ... The undeclared parameter '@p1' is used more than once in the batch being analyzed."? 70 | 71 | This is a limitation of [sys.sp\_describe\_undeclared\_parameters](https://msdn.microsoft.com/en-us/library/ff878260.aspx). 72 | 73 | To work around this limitation, you can declare another variable in your script: 74 | 75 | *) 76 | 77 | // this one would fail with above mentionned error: 78 | //let echoFail = 79 | // new SqlCommandProvider<" 80 | // select 'hello' + @name, 'your name is :' @name 81 | // ", connectionString, SingleRow = true>(connectionString) 82 | 83 | // this one is ok as @name parameter is used only once in the statement: 84 | let echoOk = 85 | new SqlCommandProvider< @" 86 | declare @theName nvarchar(max) 87 | set @theName = @name 88 | select 'hello' + @theName, 'your name is :' + @theName 89 | ", connectionString, ResultType.Tuples, SingleRow = true>(connectionString) 90 | 91 | 92 | (** 93 | ### 5. Exposing types generated by SqlCommandProvider 94 | *) 95 | 96 | (** 97 | ### 6. Reusing typed record with a custom command 98 | 99 | With a datareader obtained from a custom command you can still reuse the typed record definition through the DynamicRecord class. 100 | *) 101 | 102 | [] 103 | let getDatesQuery = "SELECT GETDATE() AS Now, GETUTCDATE() AS UtcNow" 104 | type GetDates = SqlCommandProvider 105 | 106 | open System.Data.SqlClient 107 | type SqlDataReader with 108 | member this.ToRecords<'T>() = 109 | seq { 110 | while this.Read() do 111 | let data = 112 | dict [ 113 | for i = 0 to this.VisibleFieldCount - 1 do 114 | yield this.GetName(i), this.GetValue(i) 115 | ] 116 | 117 | yield FSharp.Data.SqlClient.DynamicRecord(data) |> box |> unbox<'T> 118 | } 119 | 120 | let xs = 121 | use conn = new SqlConnection(connectionString) 122 | conn.Open() 123 | let cmd = conn.CreateCommand(CommandText = getDatesQuery) 124 | cmd.ExecuteReader().ToRecords() 125 | |> Seq.toArray 126 | 127 | (** 128 | ### 7. Why do I sometimes get ExecuteSingle and AsyncExecuteSingle options with the SqlProgrammabilityProvider? 129 | 130 | There are two cases when you would get those extra methods. 131 | 132 | * Referencing a stored procedure that returns some sort of result set you will get these extra methods. 133 | * Referencing a Table Valued Function 134 | 135 | In both cases the methods return `Option<'T>` (or `Async>`) rather than `Seq<'T>` (or `Async>`) 136 | *) 137 | -------------------------------------------------------------------------------- /docs/content/netcore.md: -------------------------------------------------------------------------------- 1 | Support for .NET Core 2 | ===================== 3 | 4 | As of version 2.0.1, a `netstandard2.0`-targeted version of FSharp.Data.SqlClient is available. 5 | This means you should be able to reference and use the type provider from a .NET Core application, 6 | with the following caveats and exceptions: 7 | 8 | * The type provider is split into two different assemblies, `FSharp.Data.SqlClient.dll` 9 | (the runtime component or RTC) and `FSharp.Data.SqlClient.DesignTime.dll` (the design-time component or DTC). 10 | * The RTC (and its dependencies) must be available at runtime; they end up in the bin folder 11 | alongside your application's compiled assemblies. The FSharp.Data.SqlClient RTC is available for 12 | both `net40` and `netstandard2.0` and is thus fully compatible with .NET Core 2.0 applications. 13 | * The DTC is required to make the provided types available to your design-time tooling and to the 14 | compiler. The FSharp.Data.SqlClient DTC *has .NET Framework-only dependencies* (`Microsoft.SqlServer.Types` 15 | and `Microsoft.SqlServer.TransactSql.ScriptDom`). As such, either .NET Framework or Mono must be 16 | installed in order to compile your .NET Core application. Additionally, you must import `fsc.props` 17 | in your .fsproj/.csproj file - please see more detailed instructions [here](https://github.com/Microsoft/visualfsharp/issues/3303). 18 | * As mentioned above, `Microsoft.SqlServer.Types` only targets .NET Framework, so you will not be able to use types such as [HierarchyId](http://technet.microsoft.com/en-us/library/bb677173.aspx) or 19 | [spatial types](http://blogs.msdn.com/b/adonet/archive/2013/12/09/microsoft-sqlserver-types-nuget-package-spatial-on-azure.aspx) from your .NET Core app. 20 | -------------------------------------------------------------------------------- /docs/content/reference architecture.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r "../../bin/FSharp.Data.SqlClient.dll" 3 | 4 | (** 5 | 6 | Beautiful Functional Architectures 7 | =================== 8 | 9 | [Project Euler. #17.](https://projecteuler.net/problem=17) 10 | 11 | F# solution: 12 | ------------------------------------- 13 | *) 14 | 15 | let ``1..9`` = 16 | [""; "one"; "two"; "three"; "four"; "five"; "six"; "seven"; "eight"; "nine"] 17 | let ``10..19`` = 18 | ["ten"; "eleven"; "twelve"; "thirteen"; "fourteen"; "fifteen"; "sixteen"; "seventeen"; "eighteen"; "nineteen"] 19 | let dozens = 20 | [""; ""; "twenty"; "thirty"; "forty"; "fifty"; "sixty"; "seventy"; "eighty"; "ninety"] 21 | 22 | let spellNumber n = 23 | [ 24 | if n = 1000 then yield! "onethousand" 25 | else 26 | let hundredsDigit = n / 100 27 | if hundredsDigit > 0 then yield! sprintf "%shundred" ``1..9``.[hundredsDigit] 28 | let moduloOf100 = n % 100 29 | if hundredsDigit <> 0 && moduloOf100 <> 0 then yield! "and" 30 | if moduloOf100 >= 10 && moduloOf100 <= 19 then yield! ``10..19``.[moduloOf100 - 10] 31 | else 32 | yield! dozens.[moduloOf100 / 10] + ``1..9``.[moduloOf100 % 10] 33 | ] 34 | 35 | [ 1 .. 1000 ] 36 | |> List.collect spellNumber 37 | |> List.length 38 | 39 | (** 40 | 41 | T-SQL solution: 42 | ------------------------------------- 43 | 44 |
 45 | 
 46 | CREATE FUNCTION dbo.SpellNumber
 47 | (
 48 | 	@n AS INT
 49 | )
 50 | RETURNS @result TABLE
 51 | (
 52 | 	 Chars NVARCHAR(MAX) NOT NULL
 53 | )
 54 | AS
 55 | BEGIN
 56 | 	IF @n = 1000
 57 | 		INSERT INTO @result VALUES ('onethousand')
 58 | 	ELSE
 59 | 		WITH Digits AS 
 60 | 		(
 61 | 			SELECT offset, value
 62 | 			FROM 
 63 | 				(VALUES 
 64 | 					(0, ''),  (1, 'one'),  (2, 'two'),  (3, 'three'),  (4, 'four'),
 65 | 					(5, 'five'),  (6, 'six'),  (7, 'seven'),  (8, 'eight'),  (9, 'nine')) 
 66 | 				AS T(offset, value)
 67 | 		),
 68 | 		TenToNineteen AS
 69 | 		(
 70 | 			SELECT offset, value
 71 | 			FROM 
 72 | 				(VALUES 
 73 | 					(0, 'ten'),  (1, 'eleven'),  (2, 'twelve'),  (3, 'thirteen'),  (4, 'fourteen'),
 74 | 					(5, 'fifteen'),  (6, 'sixteen'),  (7, 'seventeen'),  (8, 'eighteen'),  (9, 'nineteen')) 
 75 | 				AS T(offset, value)
 76 | 		),
 77 | 		Dozens AS
 78 | 		(
 79 | 			SELECT offset, value
 80 | 			FROM 
 81 | 				(VALUES 
 82 | 					(0, ''),  (1, ''),  (2, 'twenty'),  (3, 'thirty'),  (4, 'forty'),
 83 |                     (5, 'fifty'),  (6, 'sixty'),  (7, 'seventy'),  (8, 'eighty'),  (9, 'ninety')) 
 84 | 				AS T(offset, value)
 85 | 		)
 86 | 		INSERT INTO @result 
 87 | 			SELECT value + 'hundred' FROM Digits WHERE @n / 100 > 0 AND offset = @n / 100
 88 | 			UNION ALL
 89 | 			SELECT 'and' WHERE @n / 100 > 0 AND @n % 100 > 0 
 90 | 			UNION ALL
 91 | 			SELECT value FROM TenToNineteen WHERE (@n % 100) - 10 = offset
 92 | 			UNION ALL
 93 | 			SELECT value FROM Dozens WHERE (@n % 100 NOT BETWEEN 10 AND 19) AND ((@n % 100) / 10 = offset) 
 94 | 			UNION ALL
 95 | 			SELECT value FROM Digits WHERE (@n % 100 NOT BETWEEN 10 AND 19) AND ((@n % 100) % 10 = offset) 
 96 | 	RETURN
 97 | END
 98 | 
 99 | 
100 | 101 | *) 102 | 103 | open FSharp.Data 104 | 105 | [] 106 | let adventureWorks = @"Data Source=(LocalDb)\v12.0;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 107 | 108 | [] 109 | let euler17 = " 110 | WITH InfiniteSeq(N) AS 111 | ( 112 | SELECT 1 113 | UNION ALL 114 | SELECT 1 + N FROM InfiniteSeq 115 | ) 116 | 117 | SELECT SUM(LEN(ys.Chars)) 118 | FROM 119 | (SELECT TOP 1000 * FROM InfiniteSeq ) AS xs 120 | CROSS APPLY dbo.SpellNumber(xs.N) AS ys 121 | OPTION (MAXRECURSION 0) 122 | " 123 | type Euler17 = SqlCommandProvider 124 | 125 | let cmd = new Euler17() 126 | cmd.Execute() |> Option.get |> Option.get |> printfn "%i" 127 | 128 | 129 | -------------------------------------------------------------------------------- /docs/content/setup.fsx: -------------------------------------------------------------------------------- 1 | #nowarn "211" 2 | #r @"..\..\bin\net462\FSharp.Data.SqlClient.dll" 3 | #r "System.Transactions" 4 | 5 | open FSharp.Data 6 | 7 | [] 8 | let connectionString = @"Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 9 | -------------------------------------------------------------------------------- /docs/content/unit-testing.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r @"..\..\bin\net462\FSharp.Data.SqlClient.dll" 3 | #r @"..\..\packages\Test\xunit\lib\net20\xunit.dll" 4 | #r "System.Transactions" 5 | open FSharp.Data 6 | open System 7 | 8 | [] 9 | let connectionString = @"Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 10 | 11 | (** 12 | 13 | Unit-testing 14 | =================== 15 | 16 | Often there is a need to test business or presentation logic independently of database. 17 | This can be archived via [Repository](http://martinfowler.com/eaaCatalog/repository.html) pattern. 18 | 19 | *) 20 | 21 | //Command types definitions 22 | type GetEmployeesByLevel = 23 | SqlCommandProvider<" 24 | SELECT P.FirstName, P.LastName, E.JobTitle 25 | FROM HumanResources.Employee AS E 26 | JOIN Person.Person AS P ON E.BusinessEntityID = P.BusinessEntityID 27 | WHERE OrganizationLevel = @orgLevel 28 | ", connectionString> 29 | 30 | type GetSalesChampion = SqlCommandProvider<" 31 | SELECT TOP 1 FirstName, LastName 32 | FROM Sales.vSalesPerson 33 | WHERE CountryRegionName = @countryRegionName 34 | ORDER BY SalesYTD DESC 35 | " , connectionString, SingleRow = true> 36 | 37 | //Repository inteface 38 | type IRepository = 39 | abstract GetEmployeesByLevel: int16 -> list 40 | abstract GetSalesChampion: country: string -> option 41 | 42 | //Production implementation 43 | type Repository(connectionString: string) = 44 | interface IRepository with 45 | member __.GetEmployeesByLevel(orgLevel) = 46 | use cmd = new GetEmployeesByLevel(connectionString) 47 | cmd.Execute(orgLevel) |> Seq.toList 48 | 49 | member __.GetSalesChampion( region) = 50 | use cmd = new GetSalesChampion(connectionString) 51 | cmd.Execute(region) 52 | 53 | //logic to test 54 | let whoReportsToCEO(db: IRepository) = 55 | [ for x in db.GetEmployeesByLevel(1s) -> sprintf "%s %s" x.FirstName x.LastName, x.JobTitle ] 56 | 57 | let bestSalesRepInCanada(db: IRepository) = 58 | db.GetSalesChampion("Canada") 59 | 60 | //unit tests suite 61 | module MyTests = 62 | 63 | //mock the real repo 64 | let mockRepository = { 65 | new IRepository with 66 | member __.GetEmployeesByLevel(orgLevel) = 67 | if orgLevel = 1s 68 | then 69 | [ 70 | //Generated record types have single constructor that include all properties 71 | //It exists to support unit-testing. 72 | GetEmployeesByLevel.Record("David", "Bradley", JobTitle = "Marketing Manager") 73 | ] 74 | else [] 75 | 76 | member __.GetSalesChampion( region) = 77 | use cmd = new GetSalesChampion(connectionString) 78 | cmd.Execute(region) 79 | } 80 | 81 | //unit test 82 | let ``who reports to CEO``() = 83 | let expected = [ "David Bradley", "Marketing Manager" ] 84 | assert (whoReportsToCEO mockRepository = expected) 85 | //replace assert invocation above with invocation to your favorite unit testing framework 86 | //fro example Xunit.NET: Assert.Equal<_ list>(expected, actual) 87 | 88 | //unit test 89 | let ``best sales rep in Canada``() = 90 | let expected = Some( GetSalesChampion.Record("José", "Saraiva")) 91 | assert (bestSalesRepInCanada mockRepository = expected) 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /docs/content/user.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/content/whatsnew.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r "Microsoft.SqlServer.Types.dll" 3 | #r @"..\..\bin\net462\FSharp.Data.SqlClient.dll" 4 | 5 | open FSharp.Data 6 | 7 | [] 8 | let connectionString = 9 | @"Data Source=.;Initial Catalog=AdventureWorks2012;Integrated Security=True;TrustServerCertificate=true" 10 | 11 | type DB = SqlProgrammabilityProvider 12 | 13 | (** 14 | 15 | Inline T-SQL with SqlProgrammabilityProvider 16 | ------------------------------------- 17 | 18 | Starting version 1.8.1 SqlProgrammabilityProvider leverages 19 | [a new F# 4.0 feature](https://github.com/fsharp/FSharpLangDesign/blob/master/FSharp-4.0/StaticMethodArgumentsDesignAndSpec.md) 20 | to support inline T-SQL. 21 | 22 | *) 23 | do 24 | use cmd = 25 | DB.CreateCommand<" 26 | SELECT TOP(@topN) FirstName, LastName, SalesYTD 27 | FROM Sales.vSalesPerson 28 | WHERE CountryRegionName = @regionName AND SalesYTD > @salesMoreThan 29 | ORDER BY SalesYTD 30 | ">(connectionString) 31 | cmd.Execute(topN = 3L, regionName = "United States", salesMoreThan = 1000000M) |> printfn "%A" 32 | 33 | (** 34 | This makes `SqlProgrammabilityProvider` as one stop shop for both executing inline T-SQL statements 35 | and accessing to built-in objects like stored procedures, functoins and tables. 36 | Connectivity information (connection string and/or config file name) is defined in one place 37 | and doesn't have be carried around like in SqlCommandProvider case. 38 | 39 | `CreateCommand` optionally accepts connection, transaction and command timeout parameters. 40 | Any of these parameters can be ommited. 41 | *) 42 | 43 | #r "System.Transactions" 44 | 45 | do 46 | use conn = new System.Data.SqlClient.SqlConnection( connectionString) 47 | conn.Open() 48 | use tran = conn.BeginTransaction() 49 | use cmd = 50 | DB.CreateCommand<"INSERT INTO Sales.Currency VALUES(@Code, @Name, GETDATE())">( 51 | connection = conn, 52 | transaction = tran, 53 | commandTimeout = 120 54 | ) 55 | 56 | cmd.Execute( Code = "BTC", Name = "Bitcoin") |> printfn "Records affected %i" 57 | //Rollback by default. Uncomment a line below to commit the change. 58 | //tran.Commit() 59 | 60 | (** 61 | 62 | Access to command and record types 63 | ------------------------------------- 64 | 65 | `CreateMethod` combines command type definition and constructor invocation. 66 | Compare it with usage of `SqlCommandProvider` where generated command type aliased explicitly. 67 | *) 68 | 69 | let cmd1 = DB.CreateCommand<"SELECT name, create_date FROM sys.databases">(connectionString) 70 | // vs 71 | type Get42 = SqlCommandProvider<"SELECT name, create_date FROM sys.databases", connectionString> 72 | let cmd2 = new Get42(connectionString) 73 | 74 | //access to Record type 75 | type Cmd2Record = Get42.Record 76 | 77 | (** 78 | Although #3 is most verbose it has distinct advantage of providing straightforward access 79 | to type of generated command and record. 80 | This becomes important for [unit testing] or explicit type annotations scenarios. 81 | By default CreateCommand usage triggers type generation as well. 82 | A type located under Commands nested type. 83 | *) 84 | 85 | type Cmd1Command = 86 | DB.Commands.``CreateCommand,CommandText"SELECT name, create_date FROM sys.databases"`` 87 | 88 | type Cmd1Record = Cmd1Command.Record 89 | 90 | (** 91 | Type names are generated by compiler and look ugly. 92 | The type provider knows to remove illegal '=' and '@' characters 93 | but auto-competition still chokes on multi-line definitions. 94 | 95 | A workaround is to provide explicit name for generated command type 96 | *) 97 | 98 | let cmd3 = DB.CreateCommand<"SELECT name, create_date FROM sys.databases", TypeName = "Get42">(connectionString) 99 | type Cmd3Record = DB.Commands.Get42.Record 100 | 101 | (** 102 |
103 | 104 | **Note** Unfortunate downside of this amazing feature is absent of intellisense for 105 | both static method parameters and actual method parameters. This is compiler/tooling issue and tracked here: 106 | 107 | https://github.com/Microsoft/visualfsharp/issues/642
108 | https://github.com/Microsoft/visualfsharp/pull/705
109 | https://github.com/Microsoft/visualfsharp/issues/640
110 | 111 | Please help to improve quality of F# compiler and tooling by providing feedback to [F# team](https://twitter.com/VisualFSharp) 112 | or [Don Syme](https://twitter.com/dsyme). 113 | 114 |

115 | *) 116 | -------------------------------------------------------------------------------- /docs/files/img/AddRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/AddRow.png -------------------------------------------------------------------------------- /docs/files/img/ConnStrByNameAppConfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/ConnStrByNameAppConfig.png -------------------------------------------------------------------------------- /docs/files/img/ConnStrByNameUserConfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/ConnStrByNameUserConfig.png -------------------------------------------------------------------------------- /docs/files/img/ConnStrByNameUserConfig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/ConnStrByNameUserConfig2.png -------------------------------------------------------------------------------- /docs/files/img/DataRowTypedAccessors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/DataRowTypedAccessors.png -------------------------------------------------------------------------------- /docs/files/img/dapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/dapper.png -------------------------------------------------------------------------------- /docs/files/img/error_in_query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/error_in_query.png -------------------------------------------------------------------------------- /docs/files/img/logo.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/logo.pdn -------------------------------------------------------------------------------- /docs/files/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/logo.png -------------------------------------------------------------------------------- /docs/files/img/sql_file_As_CommandText_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/sql_file_As_CommandText_1.png -------------------------------------------------------------------------------- /docs/files/img/sql_file_As_CommandText_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/32c5f4bcffb7a5ead5c043113604ff11877fb576/docs/files/img/sql_file_As_CommandText_2.png -------------------------------------------------------------------------------- /docs/tools/generate.fsx: -------------------------------------------------------------------------------- 1 | // Binaries that have XML documentation (in a corresponding generated XML file) 2 | let referenceBinaries = [ ] 3 | // Web site location for the generated documentation 4 | let website = "/FSharp.Data.SqlClient" 5 | 6 | let githubLink = "http://github.com/fsprojects/FSharp.Data.SqlClient" 7 | 8 | // Specify more information about your project 9 | let info = 10 | [ "project-name", "FSharp.Data.SqlClient" 11 | "project-logo-url", "img/logo.png" 12 | "project-author", "Dmitry Morozov, Dmitry Sevastianov" 13 | "project-summary", "SqlCommandProvider provides statically typed access to input parameters and result set of T-SQL command in idiomatic F# way. SqlProgrammabilityProvider exposes Stored Procedures, User-Defined Types and User-Defined Functions in F# code." 14 | "project-github", githubLink 15 | "project-nuget", "http://www.nuget.org/packages/FSharp.Data.SqlClient" ] 16 | 17 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 18 | // this whole block is for 19 | //#load "../../.paket/load/net46/Build/FSharp.Formatting.fsx" 20 | #load "../../.paket/load/net46/Docs/FSharp.Compiler.Service.fsx" 21 | #load "../../.paket/load/net46/Docs/Microsoft.AspNet.Razor.fsx" 22 | #load "../../.paket/load/net46/Docs/RazorEngine.fsx" 23 | #r "../../packages/docs/FSharp.Formatting/lib/net40/FSharp.Markdown.dll" 24 | #r "../../packages/docs/FSharp.Formatting/lib/net40/FSharp.CodeFormat.dll" 25 | #r "../../packages/docs/FSharp.Formatting/lib/net40/CSharpFormat.dll" 26 | #r "../../packages/docs/FSharp.Formatting/lib/net40/FSharp.MetadataFormat.dll" 27 | #r "../../packages/docs/FSharp.Formatting/lib/net40/FSharp.Literate.dll" 28 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 29 | // in order to avoid following error which occurs when updating from dotnet 2 SDK to dotnet 7 30 | // error FS0239: An implementation of the file or module 'FSI_0002_FSharp.Formatting$fsx' has already been given 31 | 32 | #load "../../.paket/load/net46/Docs/FAKE.Lib.fsx" 33 | 34 | open Fake 35 | open System.IO 36 | open Fake.IO.FileSystemOperators 37 | open FSharp.Literate 38 | open FSharp.MetadataFormat 39 | 40 | // see https://github.com/fsharp/FAKE/issues/1579#issuecomment-306580820 41 | let execContext = Fake.Core.Context.FakeExecutionContext.Create false (Path.Combine(__SOURCE_DIRECTORY__, __SOURCE_FILE__)) [] 42 | Fake.Core.Context.setExecutionContext (Fake.Core.Context.RuntimeContext.Fake execContext) 43 | 44 | let root = "." 45 | 46 | // Paths with template/source/output locations 47 | let bin = __SOURCE_DIRECTORY__ @@ "../../bin/net40" 48 | let content = __SOURCE_DIRECTORY__ @@ "../content" 49 | let output = __SOURCE_DIRECTORY__ @@ "../output" 50 | let files = __SOURCE_DIRECTORY__ @@ "../files" 51 | let templates = __SOURCE_DIRECTORY__ @@ "templates" 52 | let formatting = __SOURCE_DIRECTORY__ @@ "../../packages/Docs/FSharp.Formatting/" 53 | let docTemplate = formatting @@ "templates/docpage.cshtml" 54 | 55 | // Where to look for *.csproj templates (in this order) 56 | let layoutRoots = 57 | [ templates; formatting @@ "templates" 58 | formatting @@ "templates/reference" ] 59 | 60 | // Copy static files and CSS + JS from F# Formatting 61 | let copyFiles () = 62 | Fake.IO.Shell.copyRecursive files output true |> Fake.Core.Trace.logItems "Copying file: " 63 | Fake.IO.Directory.ensure (output @@ "content") 64 | Fake.IO.Shell.copyRecursive (formatting @@ "styles") (output @@ "content") true 65 | |> Fake.Core.Trace.logItems "Copying styles and scripts: " 66 | 67 | // Build API reference from XML comments 68 | let buildReference () = 69 | Fake.IO.Shell.cleanDir (output @@ "reference") 70 | for lib in referenceBinaries do 71 | MetadataFormat.Generate 72 | ( bin @@ lib, output @@ "reference", layoutRoots, 73 | parameters = ("root", root)::info, 74 | sourceRepo = githubLink @@ "tree/master", 75 | sourceFolder = __SOURCE_DIRECTORY__ @@ ".." @@ "..", 76 | publicOnly = true ) 77 | 78 | // Build documentation from `fsx` and `md` files in `docs/content` 79 | let buildDocumentation () = 80 | let subdirs = Directory.EnumerateDirectories(content, "*", SearchOption.AllDirectories) 81 | for dir in Seq.append [content] subdirs do 82 | let sub = if dir.Length > content.Length then dir.Substring(content.Length + 1) else "." 83 | Literate.ProcessDirectory 84 | ( dir, docTemplate, output @@ sub, replacements = ("root", root)::info, 85 | layoutRoots = layoutRoots ) 86 | 87 | // Generate 88 | copyFiles() 89 | buildDocumentation() 90 | buildReference() -------------------------------------------------------------------------------- /docs/tools/templates/template.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | @Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 |
24 |
25 | 30 |

@Properties["project-name"]

31 |
32 |
33 |
34 |
35 | @RenderBody() 36 |
37 | 38 |
39 | 40 | 41 | 42 | 75 |
76 |
77 |
78 | 79 | Fork me on GitHub 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { "sdk": { "version": "8.0.100", "rollForward": "latestMinor" } } -------------------------------------------------------------------------------- /netfx.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | true 9 | 10 | 11 | /Library/Frameworks/Mono.framework/Versions/Current/lib/mono 12 | /usr/lib/mono 13 | /usr/local/lib/mono 14 | 15 | 16 | $(BaseFrameworkPathOverrideForMono)/4.5-api 17 | $(BaseFrameworkPathOverrideForMono)/4.5.1-api 18 | $(BaseFrameworkPathOverrideForMono)/4.5.2-api 19 | $(BaseFrameworkPathOverrideForMono)/4.6-api 20 | $(BaseFrameworkPathOverrideForMono)/4.6.1-api 21 | $(BaseFrameworkPathOverrideForMono)/4.6.2-api 22 | $(BaseFrameworkPathOverrideForMono)/4.7-api 23 | $(BaseFrameworkPathOverrideForMono)/4.7.1-api 24 | true 25 | 26 | 27 | $(FrameworkPathOverride)/Facades;$(AssemblySearchPaths) 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | $(DefineConstants);USE_SQL_SERVER_TYPES_ASSEMBLY;USE_SYSTEM_DATA_COMMON_DBPROVIDERFACTORIES 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /nuget/SqlClient.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | @project@ 5 | @build.number@ 6 | @authors@ 7 | @authors@ 8 | http://github.com/fsprojects/FSharp.Data.SqlClient/blob/master/LICENSE.md 9 | http://fsprojects.github.io/FSharp.Data.SqlClient/ 10 | https://raw.githubusercontent.com/fsprojects/FSharp.Data.SqlClient/master/docs/files/img/logo.png 11 | false 12 | @description@ 13 | @summary@ 14 | @releaseNotes@ 15 | Copyright 2015 16 | @tags@ 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /nuget/publish.cmd: -------------------------------------------------------------------------------- 1 | @for %%f in (..\bin\*.nupkg) do @..\.nuget\NuGet.exe push %%f -------------------------------------------------------------------------------- /paket.dependencies: -------------------------------------------------------------------------------- 1 | source https://www.nuget.org/api/v2/ 2 | generate_load_scripts: on 3 | storage: none 4 | github fsprojects/FSharp.TypeProviders.SDK:23b588d06acb8e100402523abc1d4f3f06325b8a src/ProvidedTypes.fsi 5 | github fsprojects/FSharp.TypeProviders.SDK:23b588d06acb8e100402523abc1d4f3f06325b8a src/ProvidedTypes.fs 6 | 7 | group Build 8 | source https://www.nuget.org/api/v2/ 9 | 10 | nuget Fun.Build 11 | nuget FSharp.Core 8.0.301 12 | 13 | nuget Fake.Core.Process 14 | nuget Fake.Core.ReleaseNotes 15 | nuget Fake.Core.Target 16 | nuget Fake.Core.Trace 17 | nuget Fake.DotNet.AssemblyInfoFile 18 | nuget Fake.DotNet.Cli 19 | nuget Fake.DotNet.MSBuild 20 | nuget Fake.DotNet.NuGet 21 | nuget Fake.DotNet.Testing.XUnit2 22 | nuget Fake.Tools.Git 23 | nuget FSharp.Formatting 24 | nuget FSharp.Compiler.Service 43.8.301 25 | 26 | nuget NuGet.CommandLine 27 | nuget System.Data.SqlClient 28 | 29 | nuget System.Configuration.ConfigurationManager 30 | 31 | group Docs 32 | source https://www.nuget.org/api/v2/ 33 | generate_load_scripts: on 34 | storage: packages 35 | nuget Fake.Lib 36 | nuget FSharp.Formatting = 2.4.1 37 | nuget FSharp.Compiler.Service = 0.0.36 38 | nuget RazorEngine = 3.3.0 39 | 40 | group DesignTime 41 | source https://www.nuget.org/api/v2/ 42 | framework: >= net462, >= netstandard20, net8.0 43 | storage: none 44 | 45 | nuget System.Configuration.ConfigurationManager 9.0.4 46 | nuget System.Data.Common 47 | nuget System.Data.SqlClient 48 | nuget System.Runtime.Caching 49 | nuget FSharp.Core 8.0.301 50 | nuget Microsoft.SqlServer.TransactSql.ScriptDom 51 | nuget Microsoft.SqlServer.Types 52 | 53 | group Test 54 | source https://www.nuget.org/api/v2/ 55 | 56 | nuget FSharp.Core redirects:force 57 | nuget System.Data.SqlClient 58 | nuget System.Configuration.ConfigurationManager 59 | 60 | nuget Microsoft.SqlServer.Types ~> 12 61 | nuget Newtonsoft.Json 62 | nuget xunit = 2.4.1 63 | nuget xunit.runner.visualstudio = 2.4.1 64 | 65 | group Net40 66 | source https://www.nuget.org/api/v2/ 67 | framework: net462 68 | storage: none 69 | 70 | nuget FSharp.Core = 8.0.301 71 | 72 | group TestProjects 73 | source https://www.nuget.org/api/v2/ 74 | framework: >= net462, >= netcoreapp2.0, >= netstandard2.0, net8.0 75 | storage: none 76 | 77 | nuget FSharp.Core = 8.0.301 78 | 79 | nuget System.Data.SqlClient 80 | nuget System.Configuration.ConfigurationManager 81 | 82 | group Samples 83 | source https://www.nuget.org/api/v2/ 84 | framework: >= net462, >= netcoreapp2.0, >= netstandard2.0, net8.0 85 | redirects: on 86 | 87 | nuget FSharp.Core = 8.0.301 redirects: force 88 | 89 | nuget Microsoft.AspNet.WebApi 90 | nuget Microsoft.AspNet.WebApi.Client 91 | nuget Microsoft.AspNet.WebApi.Core 92 | nuget Microsoft.AspNet.WebApi.WebHost 93 | nuget Microsoft.SqlServer.Types 94 | 95 | nuget Newtonsoft.Json redirects: force 96 | nuget FSharp.Data.SqlClient 97 | -------------------------------------------------------------------------------- /provision.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo OK 3 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | // Auto-Generated by FAKE; do not edit 2 | namespace System 3 | open System.Reflection 4 | open System.Runtime.CompilerServices 5 | 6 | [] 7 | [] 8 | [] 9 | [] 10 | [] 11 | [] 12 | do () 13 | 14 | module internal AssemblyVersionInformation = 15 | let [] AssemblyTitle = "SqlClient.DesignTime" 16 | let [] AssemblyProduct = "FSharp.Data.SqlClient.DesignTime" 17 | let [] AssemblyDescription = "SqlClient F# type providers" 18 | let [] AssemblyVersion = "2.1.3" 19 | let [] AssemblyFileVersion = "2.1.3" 20 | let [] InternalsVisibleTo = "SqlClient.Tests" 21 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/DesignTimeConnectionString.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Data.SqlClient 2 | 3 | open System.Configuration 4 | open System.IO 5 | open System 6 | open System.Collections.Generic 7 | open System.Diagnostics 8 | 9 | [] 10 | type internal DesignTimeConnectionString = 11 | | Literal of string 12 | | NameInConfig of name: string * value: string * provider: string 13 | 14 | static member Parse(s: string, resolutionFolder, fileName) = 15 | match s.Trim().Split([|'='|], 2, StringSplitOptions.RemoveEmptyEntries) with 16 | | [| "" |] -> invalidArg "ConnectionStringOrName" "Value is empty!" 17 | | [| prefix; tail |] when prefix.Trim().ToLower() = "name" -> 18 | let name = tail.Trim() 19 | let value, provider = DesignTimeConnectionString.ReadFromConfig( name, resolutionFolder, fileName) 20 | NameInConfig( name, value, provider) 21 | | _ -> 22 | Literal s 23 | 24 | static member ReadFromConfig(name, resolutionFolder, fileName) = 25 | let configFilename = 26 | if fileName <> "" then 27 | let path = Path.Combine(resolutionFolder, fileName) 28 | if not <| File.Exists path 29 | then raise <| FileNotFoundException( sprintf "Could not find config file '%s'." path) 30 | else path 31 | else 32 | // note: these filenames are case sensitive on linux 33 | let file = 34 | seq { yield "app.config" 35 | yield "App.config" 36 | yield "web.config" 37 | yield "Web.config" } 38 | |> Seq.map (fun v -> Path.Combine(resolutionFolder,v)) 39 | |> Seq.tryFind File.Exists 40 | match file with 41 | | None -> failwithf "Cannot find either App.config or Web.config." 42 | | Some file -> file 43 | 44 | let map = ExeConfigurationFileMap() 45 | map.ExeConfigFilename <- configFilename 46 | let configSection = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None).ConnectionStrings.ConnectionStrings 47 | match configSection, lazy configSection.[name] with 48 | | null, _ | _, Lazy null -> raise <| KeyNotFoundException(message = sprintf "Cannot find name %s in section of %s file." name configFilename) 49 | | _, Lazy x -> 50 | let providerName = if String.IsNullOrEmpty x.ProviderName then "System.Data.SqlClient" else x.ProviderName 51 | x.ConnectionString, providerName 52 | 53 | member this.Value = 54 | match this with 55 | | Literal value -> value 56 | | NameInConfig(_, value, _) -> value 57 | 58 | member this.RunTimeValueExpr isHostedExecution = 59 | match this with 60 | | Literal value -> <@@ value @@> 61 | | NameInConfig(name, value, _) -> 62 | <@@ 63 | let hostProcess = Process.GetCurrentProcess().ProcessName.ToUpper() 64 | if isHostedExecution 65 | || (Environment.Is64BitProcess && hostProcess = "FSIANYCPU") 66 | || (not Environment.Is64BitProcess && hostProcess = "FSI") 67 | then 68 | value 69 | else 70 | let section = ConfigurationManager.ConnectionStrings.[name] 71 | if isNull section then raise <| KeyNotFoundException(message = sprintf "Cannot find name %s in section of config file." name) 72 | else section.ConnectionString 73 | @@> 74 | 75 | member this.IsDefinedByLiteral = match this with | Literal _ -> true | _ -> false 76 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/ProvidedTypesCache.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module internal FSharp.Data.SqlClient.Cache 3 | 4 | open System.Collections.Concurrent 5 | 6 | type TypeName = string 7 | 8 | type Cache<'a>() = 9 | let cache = ConcurrentDictionary>() 10 | 11 | member __.TryGetValue(typeName: TypeName) = 12 | cache.TryGetValue(typeName) 13 | 14 | member __.GetOrAdd(typeName: TypeName, value: Lazy<'a>): 'a = 15 | cache.GetOrAdd(typeName, value).Value 16 | 17 | member __.Remove(typeName: TypeName) = 18 | cache.TryRemove(typeName) |> ignore -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/QuotationsFactory.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Data.SqlClient 2 | 3 | open System 4 | open System.Data 5 | open System.Data.SqlClient 6 | open System.Reflection 7 | open System.Collections 8 | open System.Diagnostics 9 | 10 | open Microsoft.FSharp.Quotations 11 | 12 | open FSharp.Data.SqlClient.Internals 13 | 14 | type QuotationsFactory private() = 15 | 16 | static member internal GetBody(methodName, specialization, [] bodyFactoryArgs : obj[]) = 17 | 18 | let bodyFactory = 19 | let mi = typeof.GetMethod(methodName, BindingFlags.NonPublic ||| BindingFlags.Static) 20 | assert(mi <> null) 21 | mi.MakeGenericMethod([| specialization |]) 22 | 23 | fun(args : Expr list) -> 24 | let parameters = Array.append [| box args |] bodyFactoryArgs 25 | bodyFactory.Invoke(null, parameters) |> unbox 26 | 27 | static member internal ToSqlParam(p : Parameter) = 28 | 29 | let name = p.Name 30 | let sqlDbType = p.TypeInfo.SqlDbType 31 | let isFixedLength = p.TypeInfo.IsFixedLength 32 | 33 | <@@ 34 | let x = SqlParameter(name, sqlDbType, Direction = %%Expr.Value p.Direction) 35 | 36 | if not isFixedLength then x.Size <- %%Expr.Value p.Size 37 | 38 | x.Precision <- %%Expr.Value p.Precision 39 | x.Scale <- %%Expr.Value p.Scale 40 | 41 | if x.SqlDbType = SqlDbType.Structured 42 | then 43 | let typeName: string = sprintf "%s.%s" (%%Expr.Value p.TypeInfo.Schema) (%%Expr.Value p.TypeInfo.UdttName) 44 | //done via reflection because not implemented on Mono 45 | x.GetType().GetProperty("TypeName").SetValue(x, typeName, null) 46 | 47 | if %%Expr.Value p.TypeInfo.SqlEngineTypeId = 240 48 | then 49 | x.UdtTypeName <- %%Expr.Value p.TypeInfo.TypeName 50 | x 51 | @@> 52 | 53 | static member internal OptionToObj<'T> value = <@@ match %%value with Some (x : 'T) -> box x | None -> DbNull @@> 54 | 55 | static member internal MapArrayOptionItemToObj<'T>(arr, index) = 56 | <@ 57 | let values : obj[] = %%arr 58 | values.[index] <- match unbox values.[index] with Some (x : 'T) -> box x | None -> null 59 | @> 60 | 61 | static member internal MapArrayObjItemToOption<'T>(arr, index) = 62 | <@ 63 | let values : obj[] = %%arr 64 | values.[index] <- box <| if Convert.IsDBNull(values.[index]) then None else Some(unbox<'T> values.[index]) 65 | @> 66 | 67 | static member internal MapArrayNullableItems(outputColumns : Column list, mapper : string) = 68 | let columnTypes, isNullableColumn = outputColumns |> List.map (fun c -> c.GetTypeInfoConsideringUDDT().ClrTypeFullName, c.Nullable) |> List.unzip 69 | assert(columnTypes.Length = isNullableColumn.Length) 70 | let arr = Var("_", typeof) 71 | let body = 72 | (columnTypes, isNullableColumn) 73 | ||> List.zip 74 | |> List.mapi(fun index (typeName, isNullableColumn) -> 75 | if isNullableColumn 76 | then 77 | typeof 78 | .GetMethod(mapper, BindingFlags.NonPublic ||| BindingFlags.Static) 79 | .MakeGenericMethod(Type.GetType(typeName, throwOnError = true)) 80 | .Invoke(null, [| box(Expr.Var arr); box index |]) 81 | |> unbox 82 | |> Some 83 | else 84 | None 85 | ) 86 | |> List.choose id 87 | |> List.fold (fun acc x -> 88 | Expr.Sequential(acc, x) 89 | ) <@@ () @@> 90 | Expr.Lambda(arr, body) 91 | 92 | static member internal GetNullableValueFromDataRow<'T>(exprArgs : Expr list, name : string) = 93 | <@ 94 | let row : DataRow = %%exprArgs.[0] 95 | if row.IsNull name then None else Some(unbox<'T> row.[name]) 96 | @> 97 | 98 | static member internal SetNullableValueInDataRow<'T>(exprArgs : Expr list, name : string) = 99 | <@ 100 | (%%exprArgs.[0] : DataRow).[name] <- match (%%exprArgs.[1] : option<'T>) with None -> DbNull | Some value -> box value 101 | @> 102 | 103 | static member private GetNonNullableValueFromDataRow<'T>(exprArgs : Expr list, name: string) = 104 | <@ (%%exprArgs.[0] : DataRow).[name] @> 105 | 106 | static member private SetNonNullableValueInDataRow<'T>(exprArgs : Expr list, name : string) = 107 | <@ (%%exprArgs.[0] : DataRow).[name] <- %%Expr.Coerce(exprArgs.[1], typeof) @> 108 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/Scripts/ReverseLineOrderForNotex.fsx: -------------------------------------------------------------------------------- 1 | 2 | open System.IO 3 | 4 | let releaseNotesfile = 5 | [| __SOURCE_DIRECTORY__; "..\..\.."; "RELEASE_NOTES.md" |] 6 | |> Path.Combine 7 | |> Path.GetFullPath 8 | 9 | let release xs = 10 | let isStart(s: string) = s.StartsWith("####") 11 | 12 | match xs with 13 | | h :: t when isStart h -> 14 | let current = t |> List.takeWhile (not << isStart) 15 | let upcoming = t |> List.skipWhile (not << isStart) 16 | Some(h::current, upcoming) 17 | | _ -> None 18 | 19 | let splitUpByRelease = 20 | releaseNotesfile 21 | |> File.ReadAllLines 22 | |> Array.toList 23 | |> Array.unfold release 24 | 25 | let reversed = splitUpByRelease |> Array.rev |> Array.collect Array.ofList 26 | 27 | 28 | File.WriteAllLines(releaseNotesfile, reversed) 29 | 30 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/Scripts/Scratchpad.fsx: -------------------------------------------------------------------------------- 1 | 2 | open System 3 | 4 | type Date(dt: DateTime) = 5 | member this.Year = dt.Year 6 | member this.Month = dt.Month 7 | member this.Day = dt.Day 8 | 9 | static member op_Implicit(x: DateTime) : Date = Date(x) 10 | static member op_Implicit(x: Date) : DateTime = DateTime(x.Year, x.Month, x.Day) 11 | 12 | let now = DateTime.Now 13 | 14 | let inline implicit arg = 15 | ( ^a : (static member op_Implicit : ^b -> ^a) arg) 16 | 17 | Convert.ToDateTime(Date(now)) 18 | 19 | now |> box :> Date 20 | 21 | //Convert.ChangeType(Nullable 42, typeof) 22 | Convert.ChangeType(42M, typeof) 23 | 24 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/Scripts/XE.fsx: -------------------------------------------------------------------------------- 1 | //#I @"C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\ManagementStudio\Extensions\Application" 2 | #I @"C:\Program Files\Microsoft SQL Server\120\Shared" 3 | 4 | #r "System.Transactions" 5 | #r "Microsoft.SqlServer.XE.Core.dll" 6 | #r "Microsoft.SqlServer.XEvent.Linq.dll" 7 | 8 | open Microsoft.SqlServer.XEvent.Linq 9 | open System.Data.SqlClient 10 | 11 | let connection = "Data Source=.;Initial Catalog=master;Integrated Security=True;TrustServerCertificate=true" 12 | 13 | let targetDatabase = "AdventureWorks2014" 14 | let xeSession = "XE_Alter" 15 | 16 | do 17 | use conn = new SqlConnection(connection) 18 | conn.Open() 19 | conn.ChangeDatabase(targetDatabase) 20 | let createSession = 21 | sprintf " 22 | IF NOT EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='%s') 23 | BEGIN 24 | CREATE EVENT SESSION [%s] 25 | ON SERVER 26 | ADD EVENT sqlserver.object_created 27 | ( 28 | ACTION (sqlserver.database_name, sqlserver.sql_text) 29 | WHERE (sqlserver.database_name = '%s') 30 | ), 31 | ADD EVENT sqlserver.object_deleted 32 | ( 33 | ACTION (sqlserver.database_name, sqlserver.sql_text) 34 | WHERE (sqlserver.database_name = '%s') 35 | ), 36 | ADD EVENT sqlserver.object_altered 37 | ( 38 | ACTION (sqlserver.database_name, sqlserver.sql_text) 39 | WHERE (sqlserver.database_name = '%s') 40 | ), 41 | 42 | --trash events to make buffer to flush 43 | ADD EVENT sqlos.async_io_completed, 44 | ADD EVENT sqlserver.sql_batch_completed, 45 | ADD EVENT sqlserver.sql_batch_starting, 46 | ADD EVENT sqlserver.sql_statement_completed, 47 | ADD EVENT sqlserver.sql_statement_recompile, 48 | ADD EVENT sqlserver.sql_statement_starting, 49 | ADD EVENT sqlserver.sql_transaction, 50 | ADD EVENT sqlserver.sql_transaction_commit_single_phase 51 | END 52 | 53 | IF NOT EXISTS(SELECT * FROM sys.dm_xe_sessions WHERE name='%s') 54 | BEGIN 55 | ALTER EVENT SESSION [%s] ON SERVER STATE = START 56 | END 57 | " xeSession xeSession targetDatabase targetDatabase targetDatabase xeSession xeSession 58 | use cmd = conn.CreateCommand(CommandText = createSession) 59 | cmd.ExecuteNonQuery() |> ignore 60 | 61 | do 62 | use events = new QueryableXEventData(connection, xeSession, EventStreamSourceOptions.EventStream, EventStreamCacheOptions.DoNotCache) 63 | 64 | for x in events do 65 | //printfn "Event name: %s" x.Name 66 | if x.Name = "object_altered" || x.Name = "object_created" || x.Name = "object_deleted" 67 | then 68 | let contains, ddl_phase = x.Fields.TryGetValue("ddl_phase") 69 | if contains && string ddl_phase.Value = "Commit" 70 | then 71 | printfn "ddl_phase type: %A" ddl_phase.Type 72 | 73 | let fs = x.Fields 74 | let ac = x.Actions 75 | 76 | // fs |> Seq.cast |> Seq.map (fun e -> e.Name) |> String.concat ";" |> printfn "Fields: %s" 77 | // x.Actions |> Seq.cast |> Seq.map (fun e -> e.Name) |> String.concat ";" |> printfn "Actions: %s" 78 | 79 | printfn "\nEvent %s.\nDDL Phase: %O.\nObject: id-%O; name-%O.\nDatabase: id-%O; name-%O.\nSql text: %A" x.Name fs.["ddl_phase"].Value fs.["object_id"].Value fs.["object_name"].Value fs.["database_id"].Value ac.["database_name"].Value ac.["sql_text"].Value 80 | //printfn "\nEvent %s.\nDDL Phase: %O.\nObject: id-%O; name-%O.\nDatabase: id-%O; name-%O." x.Name fs.["ddl_phase"].Value fs.["object_id"].Value fs.["object_name"].Value fs.["database_id"].Value fs.["database_name"].Value 81 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/SingleFileChangeMonitor.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Data.SqlClient 2 | 3 | open System 4 | open System.IO 5 | open System.Runtime.Caching 6 | 7 | [] 8 | type internal SingleFileChangeMonitor(path) as this = 9 | inherit ChangeMonitor() 10 | 11 | let file = new FileInfo(path) 12 | let watcher = new FileSystemWatcher( Path.GetDirectoryName(path) ) 13 | 14 | do 15 | let dispose = ref true 16 | try 17 | watcher.NotifyFilter <- NotifyFilters.LastWrite ||| NotifyFilters.FileName 18 | watcher.Changed.Add <| fun args -> this.TriggerOnFileChange(args.Name) 19 | watcher.Deleted.Add <| fun args -> this.TriggerOnFileChange(args.Name) 20 | watcher.Renamed.Add <| fun args -> this.TriggerOnFileChange(args.OldName) 21 | watcher.Error.Add <| fun _ -> this.TriggerOnChange() 22 | watcher.EnableRaisingEvents <- true 23 | dispose := false 24 | finally 25 | base.InitializationComplete() 26 | if !dispose 27 | then 28 | base.Dispose() 29 | 30 | member private __.TriggerOnChange() = base.OnChanged(state = null) 31 | member private __.TriggerOnFileChange(fileName) = 32 | if String.Compare(file.Name, fileName, StringComparison.OrdinalIgnoreCase) = 0 33 | then 34 | this.TriggerOnChange() 35 | 36 | override __.UniqueId = path + string file.LastWriteTimeUtc.Ticks + string file.Length; 37 | override __.Dispose( disposing) = if disposing then watcher.Dispose() 38 | 39 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/SingleRootTypeProvider.fs: -------------------------------------------------------------------------------- 1 | namespace ProviderImplementation.ProvidedTypes 2 | 3 | open FSharp.Data.SqlClient 4 | open Microsoft.FSharp.Core.CompilerServices 5 | open System.Reflection 6 | open System 7 | 8 | [] 9 | [] 10 | type SingleRootTypeProvider(config: TypeProviderConfig, providerName, parameters, ?isErased) as this = 11 | inherit TypeProviderForNamespaces (config, assemblyReplacementMap=[("FSharp.Data.SqlClient.DesignTime", "FSharp.Data.SqlClient")], addDefaultProbingLocation=true) 12 | 13 | let cache = new Cache() 14 | do 15 | let isErased = defaultArg isErased true 16 | let nameSpace = this.GetType().Namespace 17 | let assembly = Assembly.GetExecutingAssembly() 18 | 19 | let providerType = ProvidedTypeDefinition(assembly, nameSpace, providerName, Some typeof, hideObjectMethods = true, isErased = isErased) 20 | 21 | providerType.DefineStaticParameters( 22 | parameters = parameters, 23 | instantiationFunction = fun typeName args -> 24 | match cache.TryGetValue(typeName) with 25 | | true, cachedType -> cachedType.Value 26 | | false, _ -> 27 | let typ, monitors = this.CreateRootType(assembly, nameSpace, typeName, args) 28 | monitors 29 | |> Seq.iter(fun m -> 30 | match m with 31 | | :? System.Runtime.Caching.ChangeMonitor as monitor -> 32 | monitor.NotifyOnChanged(fun _ -> 33 | cache.Remove(typeName) 34 | this.Invalidate() 35 | monitor.Dispose() 36 | ) 37 | | _ -> () 38 | ) 39 | cache.GetOrAdd(typeName, typ) 40 | ) 41 | 42 | this.AddNamespace( nameSpace, [ providerType ]) 43 | 44 | abstract CreateRootType: assemblyName: Assembly * nameSpace: string * typeName: string * args: obj[] -> Lazy * obj[] // ChangeMonitor[] underneath but there is a problem https://github.com/fsprojects/FSharp.Data.SqlClient/issues/234#issuecomment-240694390 45 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/SqlClient.DesignTime.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | net462;net8.0 6 | FSharp.Data.SqlClient.DesignTime 7 | false 8 | true 9 | false 10 | true 11 | $(NoWarn);101 12 | ..\..\bin\typeproviders\fsharp41 13 | 14 | 20 | $(WarningsNotAsErrors);FS0026;FS3218;FS3548 21 | true 22 | true 23 | $(DefineConstants);DESIGNTIME_CODE_ONLY;IS_DESIGNTIME;WITH_LEGACY_NAMESPACE 24 | 25 | 26 | 34 | 35 | 36 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | ProvidedTypes.fsi 54 | 55 | 56 | ProvidedTypes.fs 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/SqlFileProvider.fs: -------------------------------------------------------------------------------- 1 | namespace FSharp.Data 2 | 3 | open System.IO 4 | open Microsoft.FSharp.Core.CompilerServices 5 | open ProviderImplementation.ProvidedTypes 6 | open FSharp.Data.SqlClient 7 | open System.Text 8 | 9 | [] 10 | [] 11 | type SqlFileProvider(config : TypeProviderConfig) = 12 | inherit SingleRootTypeProvider( 13 | config, 14 | "SqlFile", 15 | [ 16 | ProvidedStaticParameter("Path", typeof) 17 | ProvidedStaticParameter("ResolutionFolder", typeof, "") 18 | ProvidedStaticParameter("Encoding", typeof, "") 19 | ]) 20 | 21 | override __.CreateRootType( assembly, nameSpace, typeName, args) = 22 | let path, resolutionFolder, encoding = string args.[0], string args.[1], string args.[2] 23 | 24 | if Path.GetExtension(path) <> ".sql" 25 | then failwith "Only files with .sql extension are supported" 26 | 27 | let fullPath = 28 | if Path.IsPathRooted( path) 29 | then 30 | path 31 | else 32 | let parent = 33 | if resolutionFolder = "" then config.ResolutionFolder 34 | elif Path.IsPathRooted( resolutionFolder) then resolutionFolder 35 | else Path.Combine(config.ResolutionFolder, resolutionFolder) 36 | Path.Combine( parent, path) 37 | 38 | let typ = 39 | lazy 40 | let t = ProvidedTypeDefinition(assembly, nameSpace, typeName, baseType = Some typeof, hideObjectMethods = true) 41 | 42 | let content = 43 | if encoding = "" 44 | then File.ReadAllText( fullPath) 45 | else File.ReadAllText( fullPath, encoding = Encoding.GetEncoding( encoding)) 46 | 47 | t.AddMember <| ProvidedField.Literal("Text", typeof, content) 48 | 49 | t 50 | 51 | typ, [| new SingleFileChangeMonitor(fullPath) |] 52 | -------------------------------------------------------------------------------- /src/SqlClient.DesignTime/paket.references: -------------------------------------------------------------------------------- 1 | group DesignTime 2 | 3 | System.Configuration.ConfigurationManager 4 | System.Data.Common 5 | System.Data.SqlClient 6 | System.Runtime.Caching 7 | Microsoft.SqlServer.TransactSql.ScriptDom 8 | Microsoft.SqlServer.Types 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi.Controllers/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | True 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi.Controllers/DataAccess.fs: -------------------------------------------------------------------------------- 1 | module WebApi.DataAccess 2 | 3 | open FSharp.Data 4 | 5 | [] 6 | let AdventureWorks = "name=AdventureWorks" 7 | 8 | type QueryProducts = SqlCommandProvider< const(SqlFile<"T-SQL/Products.sql">.Text), AdventureWorks, DataDirectory = "App_Data"> 9 | 10 | //type ProductQuery = SqlFile<"T-SQL/Products.sql"> 11 | //type QueryProducts = SqlCommandProvider 12 | 13 | type AdventureWorks = SqlProgrammabilityProvider 14 | 15 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi.Controllers/HomeController.fs: -------------------------------------------------------------------------------- 1 | namespace WebApi 2 | 3 | open System.Data.SqlClient 4 | open System.Net 5 | open System.Net.Http 6 | open System.Web.Http 7 | open System.Web.Configuration 8 | 9 | open DataAccess 10 | 11 | module SqlCommand = 12 | let inline create() : 'a = 13 | let designTimeConnectionString = (^a : (static member get_ConnectionStringOrName : unit -> string) ()) 14 | 15 | match designTimeConnectionString with 16 | | DataAccess.AdventureWorks -> 17 | //get connection string at run-time 18 | let adventureWorks = WebConfigurationManager.ConnectionStrings.["AdventureWorks2012"].ConnectionString 19 | //create command instance with connection string and command timeout override 20 | (^a : (new : string * int -> ^a) (adventureWorks, 30)) 21 | 22 | | _ -> failwithf "Unrecognized command type %s" typeof<'a>.FullName 23 | 24 | 25 | type HomeController() = 26 | inherit ApiController() 27 | 28 | member this.Get() = this.Get(7L, System.DateTime.Parse "2002-06-01") 29 | 30 | //http://localhost:61594/?top=4&sellStartDate=2002-07-01 31 | member this.Get(top, sellStartDate) = 32 | async { 33 | let cmd : QueryProducts = SqlCommand.create() 34 | 35 | //or get connnection info from web.config 36 | //let cmd = QueryProducts() 37 | 38 | let! data = cmd.AsyncExecute(top = top, SellStartDate = sellStartDate) 39 | return this.Request.CreateResponse(HttpStatusCode.OK, data) 40 | } |> Async.StartAsTask 41 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi.Controllers/T-SQL/Products.sql: -------------------------------------------------------------------------------- 1 | --uncomment for design time testing 2 | --DECLARE 3 | -- @top AS BIGINT = 10, 4 | -- @SellStartDate AS DATETIME = '2002-06-01' 5 | 6 | SELECT TOP (@top) Name AS ProductName, SellStartDate 7 | FROM Production.Product 8 | WHERE SellStartDate > @SellStartDate -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi.Controllers/paket.references: -------------------------------------------------------------------------------- 1 | group Samples 2 | FSharp.Core 3 | FSharp.Data.SqlClient 4 | Microsoft.AspNet.WebApi.Client 5 | Microsoft.AspNet.WebApi.Core 6 | Newtonsoft.Json 7 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="WebApi.Global" Language="C#" %> 2 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http.Headers; 5 | using System.Web; 6 | using System.Web.Http; 7 | using System.Web.Security; 8 | using System.Web.SessionState; 9 | 10 | namespace WebApi 11 | { 12 | public class Global : System.Web.HttpApplication 13 | { 14 | 15 | protected void Application_Start(object sender, EventArgs e) 16 | { 17 | GlobalConfiguration.Configuration.Routes.MapHttpRoute("DefaultAPI", "{controller}/{id}", new { controller = "Home", id = RouteParameter.Optional }); 18 | GlobalConfiguration.Configuration.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebApi")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebApi")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("eb9e0f3a-b8ec-4341-bf09-f10e50a23cbd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/paket.references: -------------------------------------------------------------------------------- 1 | group Samples 2 | FSharp.Core 3 | FSharp.Data.SqlClient 4 | Microsoft.AspNet.WebApi 5 | Microsoft.AspNet.WebApi.Client 6 | Microsoft.AspNet.WebApi.Core 7 | Microsoft.AspNet.WebApi.WebHost 8 | Newtonsoft.Json -------------------------------------------------------------------------------- /src/SqlClient.Samples/WebApi/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | True 30 | 31 | 32 | 33 | 34 | True 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WpfDataBinding/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | True 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/SqlClient.Samples/WpfDataBinding/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |