diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/AssemblyInfo.fs b/src/TypeProviderUsers/TypeProviderUser.TSQL/AssemblyInfo.fs new file mode 100644 index 0000000..8f5a576 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/AssemblyInfo.fs @@ -0,0 +1,41 @@ +namespace TypeProviderUser.SQLite.AssemblyInfo + +open System.Reflection +open System.Runtime.CompilerServices +open System.Runtime.InteropServices + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[] +[] +[] +[] +[] +[] +[] +[] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [] +[] +[] + +do + () \ No newline at end of file diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/Shared.fs b/src/TypeProviderUsers/TypeProviderUser.TSQL/Shared.fs new file mode 100644 index 0000000..ec03ba0 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/Shared.fs @@ -0,0 +1,80 @@ +namespace TypeProviderUser.TSQL +open Rezoom.SQL +open Rezoom.SQL.Mapping +open Rezoom.SQL.Migrations +open Rezoom.SQL.Synchronous +open System.IO + +type TestModel = SQLModel<"."> + +type TestData = SQL<""" +delete from ArticleComments; +delete from Articles; +delete from Users; +delete from Pictures; + +insert into Pictures(SHA256, PNGData) +values ( x'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + , x'' + ); +insert into Pictures(SHA256, PNGData) +values ( x'0000000000000000000000000000000000000000000000000000000000000000' + , x'' + ); + +vendor tsql { + set identity_insert dbo.Users on +}; + +insert into Users(Id,Name, Email, ProfilePictureSHA256, Created, RandomId) +values ( 1, 'Homer' + , 'homer.simpson@springfieldnuclear.com' + , x'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' + , 2017-01-01T00:00:00 + , (newid()) + ); +insert into Users(Id, Name, Email, ProfilePictureSHA256, Created, RandomId) +values ( 2, 'Marge' + , 'marge@globex.com' + , x'0000000000000000000000000000000000000000000000000000000000000000' + , 2017-01-01T00:00:00 + , (newid()) + ); + +vendor tsql { + set identity_insert dbo.Users off +}; + +insert into Articles(AuthorId, ArticleTitle, ArticleText) +values ( (select Id from Users where Name = 'Homer') + , 'My first review as a food critic.' + , 'Mmmmmmm... donuts' + ); +insert into Articles(AuthorId, ArticleTitle, ArticleText) +values ( (select Id from Users where Name = 'Homer') + , 'My second review as a food critic.' + , 'Mmmmmmm... beer' + ); +insert into ArticleComments(AuthorId, ArticleId, CommentText) +values ( (select Id from Users where Name = 'Marge') + , (select Id from Articles where ArticleTitle = 'My first review as a food critic.') + , 'Are you sure you should be eating so many donuts?' + ); +insert into ArticleComments(AuthorId, ArticleId, CommentText) +values ( (select Id from Users where Name = 'Marge') + , (select Id from Articles where ArticleTitle = 'My second review as a food critic.') + , 'Are you sure you should be drinking so many beers?' + ); +"""> + +[] +module Helpers = + let runOnTestData (cmd : Command<'a>) = + TestModel.Migrate(MigrationConfig.Default) + do + use cxt = new ConnectionContext() + TestData.Command().Execute(cxt) + TestModel.Migrate(MigrationConfig.Default) + use cxt = new ConnectionContext() + TestData.Command().Execute(cxt) + cmd.Execute(cxt) \ No newline at end of file diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/TestSelects.fs b/src/TypeProviderUsers/TypeProviderUser.TSQL/TestSelects.fs new file mode 100644 index 0000000..d959c05 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/TestSelects.fs @@ -0,0 +1,167 @@ +module TypeProviderUser.TSQL.TestSelects +open System +open System.Threading +open System.Threading.Tasks +open NUnit.Framework +open FsUnit +open Rezoom +open Rezoom.SQL +open Rezoom.SQL.Plans +open MBrace.FsPickler +open Rezoom + +type TestEqualInteger = SQL<""" +select * from Users where Id = @userId +"""> + +[] +let ``test = integer`` () = + let results = TestEqualInteger.Command(1L) |> runOnTestData + printfn "%A" results + Assert.AreEqual + ( [ "Homer" ] + , [ for r in results -> r.Name ] |> List.sort + ) + +type TestInInteger = SQL<""" +select * from Users where Id in @userIds +"""> + +[] +let ``test in integer`` () = + let results = TestInInteger.Command([| 1L; 2L |]) |> runOnTestData + printfn "%A" results + Assert.AreEqual + ( [ "Homer"; "Marge" ] + , [ for r in results -> r.Name ] |> List.sort + ) + +type TestInByteArrays = SQL<""" +select * from Pictures where SHA256 in @hashes +"""> + +[] +let ``test in byte arrays`` () = + let results = TestInByteArrays.Command([| Array.create 32 0uy; Array.create 32 0xffuy |]) |> runOnTestData + printfn "%A" results + Assert.AreEqual([ [||]; [||] ], [ for r in results -> r.PNGData ]) + +type TestDateTimeParameter = SQL<""" +select * from Users where Created > @created +"""> + +[] +let ``test datetime parameter`` () = + let results = TestDateTimeParameter.Command(DateTime.UtcNow) |> runOnTestData + printfn "%A" results + +type TestOptionalDateTimeParameter = SQL<""" +select * from Users where Created > @created or @created is null +"""> + +[] +let ``test optional datetime parameter`` () = + let results = TestOptionalDateTimeParameter.Command(Some DateTime.UtcNow) |> runOnTestData + printfn "%A" results + +type TestGuidParameter = SQL<""" +select * from Users where RandomId = @id; +"""> + +[] +let ``test guid parameter`` () = + let results = TestGuidParameter.Command(Guid.NewGuid()) |> runOnTestData + printfn "%A" results + +type TestOptionalGuidParameter = SQL<""" +select * from Users where RandomId = @id or @id is null +"""> + + +type TestInEmptySet = SQL<""" +select * from Users where RandomId in @ids +"""> + +[] +let ``test in empty set`` () = + let results = TestInEmptySet.Command([||]) |> runOnTestData + Assert.AreEqual(0, results.Count) + printfn "%A" results + +[] +let ``test optional guid parameter`` () = + let results = TestOptionalGuidParameter.Command(Some (Guid.NewGuid())) |> runOnTestData + printfn "%A" results + +type TestEmptyMany = SQL<""" +select p.*, many Children(c.*) +from Users p +left join Users c on false +"""> + +[] +let ``test empty many`` () = + let results = TestEmptyMany.Command() |> runOnTestData + Assert.AreEqual(2, results.Count) + for result in results do + Assert.AreEqual(0, result.Children.Count) + printfn "%A" results + +[] +let ``replay works`` () = + let plan = + plan { + let! r1 = TestInInteger.Command([| 1L |]).Plan() + let! r2 = TestInInteger.Command([| 2L |]).Plan() + return r1.[0].Email, r2.[0].Email + } + let config = Execution.ExecutionConfig.Default + let serializer = + let bin = FsPickler.CreateBinarySerializer() + { new Replay.IReplaySerializer with + member __.Serialize(o) = bin.Pickle(o) + member __.Deserialize(o) = bin.UnPickle(o) + } + let mutable saved = None + let save state arr = + saved <- Some (arr()) + let recording = + Replay.RecordingExecutionStrategy.Create + ( Execution.defaultExecutionStrategy + , serializer + , save + ) + let played = recording.Execute(config, plan, CancellationToken.None).Result + match saved with + | None -> failwith "not saved" + | Some blob -> + let replayed = (Replay.replay config serializer blob).Result + if played = unbox replayed then + () + else failwith "not equal" + +type InsertPicture = SQL<"insert into Pictures row SHA256 = @sha, PNGData = @png"> + +[] +let ``lotsa parameters`` () = + let task = + plan { + let g() = Guid.NewGuid().ToByteArray() + for i in batch [0..2000] do + do! InsertPicture.Command(g(), g()).Plan() + } |> Execution.execute Execution.ExecutionConfig.Default + task.Wait() + +open Rezoom.SQL.Raw +open System.Data + +type RawSQLQuery = SQL<""" + select * from Users where unsafe_inject_raw(@whereClause) +"""> + +[] +let ``test raw sql parameter`` () = + let results = + RawSQLQuery.Command(whereClause = [| sql "1="; arg 1 |]) |> runOnTestData + for result in results do + printfn "%A" result.Email diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/TypeProviderUser.TSQL.fsproj b/src/TypeProviderUsers/TypeProviderUser.TSQL/TypeProviderUser.TSQL.fsproj new file mode 100644 index 0000000..c0ef506 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/TypeProviderUser.TSQL.fsproj @@ -0,0 +1,33 @@ + + + + net45 + + + + + + + + + + + + + + + ..\..\Rezoom.SQL.Provider\bin\Debug\Rezoom.dll + + + ..\..\Rezoom.SQL.Provider\bin\Debug\Rezoom.SQL.Mapping.dll + + + ..\..\Rezoom.SQL.Provider\bin\Debug\Rezoom.SQL.Provider.dll + + + + + + + + diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/V1.model.sql b/src/TypeProviderUsers/TypeProviderUser.TSQL/V1.model.sql new file mode 100644 index 0000000..119f071 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/V1.model.sql @@ -0,0 +1,32 @@ +create table Pictures +( SHA256 binary(32) primary key +, PNGData binary(4000) +); + +create table Users +( Id int64 primary key autoincrement +, Name string(80) +, Email string(254) +, ProfilePictureSHA256 binary(32) null references Pictures(SHA256) +, Created datetime +, RandomId guid +); + +create table Articles +( Id int64 primary key autoincrement +, AuthorId int64 references Users(Id) +, ArticleTitle string(80) +, ArticleText string(4000) +); + +create index IX_Articles_AuthorId on Articles(AuthorId); + +create table ArticleComments +( Id int64 primary key autoincrement +, ArticleId int64 references Articles(Id) +, AuthorId int64 references Users(Id) +, CommentText string(512) +); + +create index IX_ArticleComments_AuthorId on ArticleComments(AuthorId); + diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/app.config b/src/TypeProviderUsers/TypeProviderUser.TSQL/app.config new file mode 100644 index 0000000..5e887da --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/app.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/packages.config b/src/TypeProviderUsers/TypeProviderUser.TSQL/packages.config new file mode 100644 index 0000000..93e5504 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/TypeProviderUsers/TypeProviderUser.TSQL/rzsql.json b/src/TypeProviderUsers/TypeProviderUser.TSQL/rzsql.json new file mode 100644 index 0000000..9b3dc65 --- /dev/null +++ b/src/TypeProviderUsers/TypeProviderUser.TSQL/rzsql.json @@ -0,0 +1,3 @@ +{ + "backend": "tsql" +} \ No newline at end of file diff --git a/src/TypeProviderUsers/TypeProviderUsers.sln b/src/TypeProviderUsers/TypeProviderUsers.sln index 3691113..8d5ccd7 100644 --- a/src/TypeProviderUsers/TypeProviderUsers.sln +++ b/src/TypeProviderUsers/TypeProviderUsers.sln @@ -1,12 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.16 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29424.173 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TypeProviderUser.SQLite", "TypeProviderUser.SQLite\TypeProviderUser.SQLite.fsproj", "{0F05CBC1-FFCA-41B0-89FC-DB11D13D823C}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TypeProviderUser.Postgres", "TypeProviderUser.Postgres\TypeProviderUser.Postgres.fsproj", "{EA4DD44F-F7E0-4953-961A-892D4BEC43BD}" EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TypeProviderUser.TSQL", "TypeProviderUser.TSQL\TypeProviderUser.TSQL.fsproj", "{EBBDDEAD-2646-40A9-BE39-8F25762D2875}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,8 +23,15 @@ Global {EA4DD44F-F7E0-4953-961A-892D4BEC43BD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA4DD44F-F7E0-4953-961A-892D4BEC43BD}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA4DD44F-F7E0-4953-961A-892D4BEC43BD}.Release|Any CPU.Build.0 = Release|Any CPU + {EBBDDEAD-2646-40A9-BE39-8F25762D2875}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBBDDEAD-2646-40A9-BE39-8F25762D2875}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBBDDEAD-2646-40A9-BE39-8F25762D2875}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBBDDEAD-2646-40A9-BE39-8F25762D2875}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5D585200-02DB-4083-915A-12A1F78C5DB6} + EndGlobalSection EndGlobal