diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..041b681
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "paket": {
+ "version": "6.2.1",
+ "commands": [
+ "paket"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 90a50b0..d7045d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ local.properties
.classpath
.settings/
.loadpath
+.idea/
# External tool builders
.externalToolBuilders/
diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets
new file mode 100644
index 0000000..4deb15b
--- /dev/null
+++ b/.paket/Paket.Restore.targets
@@ -0,0 +1,557 @@
+
+
+
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+
+ $(MSBuildVersion)
+ 15.0.0
+ false
+ true
+
+ true
+ $(MSBuildThisFileDirectory)
+ $(MSBuildThisFileDirectory)..\
+ $(PaketRootPath)paket-files\paket.restore.cached
+ $(PaketRootPath)paket.lock
+ classic
+ proj
+ assembly
+ native
+ /Library/Frameworks/Mono.framework/Commands/mono
+ mono
+
+
+ $(PaketRootPath)paket.bootstrapper.exe
+ $(PaketToolsPath)paket.bootstrapper.exe
+ $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\
+
+ "$(PaketBootStrapperExePath)"
+ $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"
+
+
+
+
+ true
+ true
+
+
+ True
+
+
+ False
+
+ $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/'))
+
+
+
+
+
+
+
+
+ $(PaketRootPath)paket
+ $(PaketToolsPath)paket
+
+
+
+
+
+ $(PaketRootPath)paket.exe
+ $(PaketToolsPath)paket.exe
+
+
+
+
+
+ <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json"))
+ <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"'))
+ <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false
+
+
+
+
+
+
+
+
+
+
+ <_PaketCommand>dotnet paket
+
+
+
+
+
+ $(PaketToolsPath)paket
+ $(PaketBootStrapperExeDir)paket
+
+
+ paket
+
+
+
+
+ <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))
+ <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)"
+ <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
+ <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(NoWarn);NU1603;NU1604;NU1605;NU1608
+ false
+ true
+
+
+
+
+
+
+
+
+ $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))
+
+
+
+
+
+
+ $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))
+ $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))
+
+
+
+
+ %(PaketRestoreCachedKeyValue.Value)
+ %(PaketRestoreCachedKeyValue.Value)
+
+
+
+
+ true
+ false
+ true
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached
+
+ $(MSBuildProjectFullPath).paket.references
+
+ $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references
+
+ $(MSBuildProjectDirectory)\paket.references
+
+ false
+ true
+ true
+ references-file-or-cache-not-found
+
+
+
+
+ $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)'))
+ $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)'))
+ references-file
+ false
+
+
+
+
+ false
+
+
+
+
+ true
+ target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths)
+
+
+
+
+
+
+
+
+
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length)
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4])
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5])
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[6])
+ $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[7])
+
+
+ %(PaketReferencesFileLinesInfo.PackageVersion)
+ All
+ runtime
+ $(ExcludeAssets);contentFiles
+ $(ExcludeAssets);build;buildMultitargeting;buildTransitive
+ true
+ true
+
+
+
+
+ $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools
+
+
+
+
+
+
+
+
+ $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0])
+ $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1])
+
+
+ %(PaketCliToolFileLinesInfo.PackageVersion)
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+ <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/>
+
+
+
+
+
+ $(MSBuildProjectDirectory)/$(MSBuildProjectFile)
+ true
+ false
+ true
+ false
+ true
+ false
+ true
+ false
+ true
+ false
+ true
+ $(PaketIntermediateOutputPath)\$(Configuration)
+ $(PaketIntermediateOutputPath)
+
+
+
+ <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MongoDB.FSharp.BackwardCompatTests/BackwardCompatTest.fs b/MongoDB.FSharp.BackwardCompatTests/BackwardCompatTest.fs
new file mode 100644
index 0000000..4d8faf3
--- /dev/null
+++ b/MongoDB.FSharp.BackwardCompatTests/BackwardCompatTest.fs
@@ -0,0 +1,47 @@
+module ``Acceptance Tests``
+
+open Mongo2Go
+open MongoDB.Bson
+open MongoDB.Driver
+open MongoDB.FSharp
+open Xunit
+
+module TestUtils =
+ let newBsonObjectId() = ObjectId.GenerateNewId() |> BsonObjectId
+
+ let findById id (collection: IMongoCollection) =
+ let filter = FilterDefinition.op_Implicit(BsonDocument("_id", id))
+ collection.Find(filter).ToList() |> Seq.head
+
+open TestUtils
+
+type ObjectWithOptions() =
+ member val Id : BsonObjectId = newBsonObjectId() with get, set
+ member val Age : int option = None with get, set
+
+type ``Backward compatibility tests``() =
+ let runner = MongoDbRunner.Start()
+ let db = MongoClient(runner.ConnectionString).GetDatabase("IntegrationTest")
+ do Serializers.Register({ UseOptionNull = false })
+
+ interface System.IDisposable with
+ member this.Dispose() = runner.Dispose()
+
+ []
+ member this.``It can serialize option types``() =
+ let collection = db.GetCollection "objects"
+ let obj = ObjectWithOptions()
+ obj.Age <- Some 42
+ collection.InsertOne obj
+
+ let collection = db.GetCollection "objects"
+ let fromDb = collection |> findById obj.Id
+ let age = fromDb.GetElement("Age")
+ Assert.NotNull(age);
+ Assert.Equal("Some", age.Value.AsBsonDocument.GetElement("_t").Value.AsString)
+ let value = age.Value.AsBsonDocument.GetElement("_v").Value
+ Assert.True(value.IsBsonArray)
+ let array = value.AsBsonArray
+ Assert.Equal(1, array.Count)
+ Assert.Equal(42, array.[0].AsInt32)
+
diff --git a/MongoDB.FSharp.BackwardCompatTests/MongoDB.FSharp.BackwardCompatTests.fsproj b/MongoDB.FSharp.BackwardCompatTests/MongoDB.FSharp.BackwardCompatTests.fsproj
new file mode 100644
index 0000000..49a4880
--- /dev/null
+++ b/MongoDB.FSharp.BackwardCompatTests/MongoDB.FSharp.BackwardCompatTests.fsproj
@@ -0,0 +1,30 @@
+
+
+
+ net6.0
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MongoDB.FSharp.BackwardCompatTests/Program.fs b/MongoDB.FSharp.BackwardCompatTests/Program.fs
new file mode 100644
index 0000000..0695f84
--- /dev/null
+++ b/MongoDB.FSharp.BackwardCompatTests/Program.fs
@@ -0,0 +1 @@
+module Program = let [] main _ = 0
diff --git a/MongoDB.FSharp.BackwardCompatTests/Tests.fs b/MongoDB.FSharp.BackwardCompatTests/Tests.fs
new file mode 100644
index 0000000..7d11a64
--- /dev/null
+++ b/MongoDB.FSharp.BackwardCompatTests/Tests.fs
@@ -0,0 +1,8 @@
+module Tests
+
+open System
+open Xunit
+
+[]
+let ``My test`` () =
+ Assert.True(true)
diff --git a/MongoDB.FSharp.BackwardCompatTests/paket.references b/MongoDB.FSharp.BackwardCompatTests/paket.references
new file mode 100644
index 0000000..111f5fa
--- /dev/null
+++ b/MongoDB.FSharp.BackwardCompatTests/paket.references
@@ -0,0 +1,6 @@
+FSharp.Core
+xunit
+unquote
+Mongo2Go
+Microsoft.NET.Test.Sdk
+xunit.runner.visualstudio
\ No newline at end of file
diff --git a/MongoDB.FSharp.Tests/AcceptanceTests.fs b/MongoDB.FSharp.Tests/AcceptanceTests.fs
index 23f7475..5a0ff7e 100644
--- a/MongoDB.FSharp.Tests/AcceptanceTests.fs
+++ b/MongoDB.FSharp.Tests/AcceptanceTests.fs
@@ -1,20 +1,19 @@
namespace ``Acceptance Tests``
+open Mongo2Go
open Xunit
open Swensen.Unquote
-open Swensen.Unquote.Assertions
open MongoDB.Bson
open MongoDB.Driver
-open MongoDB.Driver.Linq
open MongoDB.FSharp
open System.Linq
-open Microsoft.FSharp.Linq
open TestUtils
+open Xunit.Abstractions
type ObjectWithList() =
- member val Id : BsonObjectId = BsonObjectId.GenerateNewId() with get, set
+ member val Id : BsonObjectId = newBsonObjectId() with get, set
member val List : string list = [] with get, set
type RecordType = {
@@ -39,85 +38,86 @@ type DimmerSwitch =
| Dim of int
| DimMarquee of int * string
| On
-
-type ObjectWithOptions() =
- member val Id : BsonObjectId = BsonObjectId.GenerateNewId() with get, set
- member val Age : int option = None with get, set
+
+type RecordWithList = {
+ Id: BsonObjectId
+ IntVal: int
+ DoubleVal: double
+ ListVal: int list
+ OptionVal: int option
+}
type ObjectWithDimmer() =
- member val Id : BsonObjectId = BsonObjectId.GenerateNewId() with get, set
+ member val Id : BsonObjectId = newBsonObjectId() with get, set
member val Switch : DimmerSwitch = Off with get, set
type ObjectWithDimmers() =
- member val Id : BsonObjectId = BsonObjectId.GenerateNewId() with get, set
+ member val Id : BsonObjectId = newBsonObjectId() with get, set
member val Kitchen : DimmerSwitch = Off with get, set
member val Bedroom1 : DimmerSwitch = Off with get, set
member val Bedroom2 : DimmerSwitch = Off with get, set
-type ``When serializing lists``() =
- let db = MongoDatabase.Create "mongodb://localhost/test"
- do
- Serializers.Register()
+type ``When serializing lists``(output: ITestOutputHelper) =
+ let runner = MongoDbRunner.Start()
+ let db = MongoClient(runner.ConnectionString).GetDatabase("IntegrationTest")
+ do Serializers.Register()
interface System.IDisposable with
- member this.Dispose() =
- db.DropCollection "objects" |> ignore
- db.DropCollection "persons" |> ignore
+ member this.Dispose() = runner.Dispose()
- /// Seems to be fixed in version 1.5 of the C# driver
[]
member this.``It can serialize an object with a list``() =
let collection = db.GetCollection "objects"
let obj = ObjectWithList()
obj.List <- [ "hello"; "world" ]
- collection.Save obj |> ignore
+ collection.InsertOne(obj)
- let genCollection = db.GetCollection "objects"
- let fromDb = genCollection.FindOne(new QueryDocument("_id", obj.Id))
- let array = fromDb.["List"].AsBsonArray
- Assert.Equal(2, array.Count)
+ let genCollection = db.GetCollection "objects"
+ let fromDb = genCollection.Find(fun x -> x.Id = obj.Id).ToList().First()
+ let array = fromDb.List
+ test <@ List.length array = 2 @>
[]
member this.``It can deserialze lists``() =
let list = BsonArray([ "hello"; "world" ])
- let id = BsonObjectId.GenerateNewId()
+ let id = newBsonObjectId()
let document = BsonDocument([ BsonElement("_id", id); BsonElement("List", list) ])
- let collection = db.GetCollection "objects"
- collection.Save document |> ignore
+ let collection = db.GetCollection "objects"
+ collection.InsertOne document
let collection = db.GetCollection "objects"
- let fromDb = collection.FindOne(new QueryDocument("_id", id))
+ let fromDb = collection.Find(fun x -> x.Id = id).ToList().First()
let array = fromDb.List
- Assert.Equal(2, array.Length)
+ test <@ List.length array = 2 @>
[]
member this.``It can serialize records``() =
let collection = db.GetCollection "objects"
- let obj = { Id = BsonObjectId.GenerateNewId(); Name = "test" }
- collection.Save obj |> ignore
+ let obj = { Id = newBsonObjectId(); Name = "test" }
+ collection.InsertOne obj
- let genCollection = db.GetCollection "objects"
- let fromDb = genCollection.FindOne(new QueryDocument("_id", obj.Id))
- let test = fromDb.["Name"].AsString
- Assert.Equal("test", test)
+ let genCollection = db.GetCollection "objects"
+ let fromDb = genCollection |> findById obj.Id
+ let name = fromDb["Name"].AsString
+ test <@ name = "test" @>
[]
member this.``It can deserialize records``() =
- let id = BsonObjectId.GenerateNewId()
+ let id = newBsonObjectId()
let document = BsonDocument([BsonElement("_id", id); BsonElement("Name", BsonString("value"))])
let collection = db.GetCollection "objects"
- collection.Save(document) |> ignore
+ collection.InsertOne(document)
let collection = db.GetCollection("objects")
- let fromDb = collection.FindOneById(id)
+ let fromDb = collection.Find(fun x -> x.Id = id).ToList().First()
Assert.NotNull(fromDb)
Assert.Equal("value", fromDb.Name)
[]
member this.``It can serialize and deserialize nested records``() =
let collection = db.GetCollection "persons"
- let obj = { Id = BsonObjectId.GenerateNewId(); PersonName = "test"; Age = 33; Childs = [{ChildName = "Adrian"; Age = 3}] }
- collection.Save obj |> ignore
+ let obj = { Id = newBsonObjectId(); PersonName = "test"; Age = 33; Childs = [{ChildName = "Adrian"; Age = 3}] }
+ collection.InsertOne obj
let genCollection = db.GetCollection "persons"
let person = query {
@@ -137,34 +137,15 @@ type ``When serializing lists``() =
Assert.Equal("Adrian", child.ChildName)
Assert.Equal(3, child.Age)
-
- []
- member this.``It can serialize option types``() =
- let collection = db.GetCollection "objects"
- let obj = ObjectWithOptions()
- obj.Age <- Some 42
- collection.Save obj |> ignore
-
- let collection = db.GetCollection "objects"
- let fromDb = collection.FindOneById(obj.Id)
- let age = fromDb.GetElement("Age")
- Assert.NotNull(age);
- Assert.Equal("Some", age.Value.AsBsonDocument.GetElement("_t").Value.AsString)
- let value = age.Value.AsBsonDocument.GetElement("_v").Value
- Assert.True(value.IsBsonArray)
- let array = value.AsBsonArray
- Assert.Equal(1, array.Count)
- Assert.Equal(42, array.[0].AsInt32)
-
[]
member this.``It can serialize DimmerSwitch types``() =
- let collection = db.GetCollection "objects"
+ let collection = db.GetCollection "objects"
let obj = ObjectWithDimmer()
obj.Switch <- DimMarquee(42, "loser")
- collection.Save obj |> ignore
+ collection.InsertOne obj
- let collection = db.GetCollection "objects"
- let fromDb = collection.FindOneById(obj.Id)
+ let collection = db.GetCollection "objects"
+ let fromDb = collection |> findById obj.Id
let switch = fromDb.GetElement("Switch")
Assert.NotNull(switch);
Assert.Equal("DimMarquee", switch.Value.AsBsonDocument.GetElement("_t").Value.AsString)
@@ -174,22 +155,59 @@ type ``When serializing lists``() =
Assert.Equal(2, array.Count)
Assert.Equal(42, array.[0].AsInt32)
Assert.Equal("loser", array.[1].AsString)
+
+ []
+ member this.``It can serialize option types``() =
+ let collection = db.GetCollection "objects"
+ let obj = ObjectWithOptions()
+ obj.Age <- Some 42
+ collection.InsertOne obj
+
+ let collection = db.GetCollection "objects"
+ let fromDb = collection |> findById obj.Id
+ let age = fromDb.GetElement("Age")
+ let v = age.Value
+ test <@ v.AsInt32 = 42 @>
+
+ []
+ member this.``It can serialize option types with None``() =
+ let collection = db.GetCollection "objects"
+ let obj = ObjectWithOptions()
+ obj.Age <- None
+ collection.InsertOne obj
+
+ let collection = db.GetCollection "objects"
+ let fromDb = collection |> findById obj.Id
+ let age = fromDb.GetElement("Age")
+ let v = age.Value
+ test <@ v.AsBsonNull = BsonNull.Value @>
[]
member this.``It can deserialize option types``() =
- let id = BsonObjectId.GenerateNewId()
+ let id = newBsonObjectId()
let arrayPart = BsonArray([ BsonInt32(42) ])
- let structure = BsonDocument(BsonElement("_t", BsonString("Some")), BsonElement("_v", arrayPart))
- let document = BsonDocument(BsonElement("_id", id), BsonElement("Age", structure))
+ let structure = BsonDocument([BsonElement("_t", BsonString("Some")); BsonElement("_v", arrayPart)])
+ let document = BsonDocument([BsonElement("_id", id); BsonElement("Age", structure)])
let collection = db.GetCollection "objects"
- collection.Save(document) |> ignore
+ collection.InsertOne(document)
let collection = db.GetCollection "objects"
- let fromDb = collection.FindOneById id
+ let fromDb = collection.Find(fun x -> x.Id = id).ToList().First()
match fromDb.Age with
| Some 42 -> ()
| _ -> fail "expected Some 42 but got something else"
+ []
+ member this.``It can deserialize option types from undefined``() =
+ let id = newBsonObjectId()
+ let document = BsonDocument([BsonElement("_id", id)])
+ let collection = db.GetCollection "objects"
+ collection.InsertOne(document)
+
+ let collection = db.GetCollection "objects"
+ let fromDb = collection.Find(fun x -> x.Id = id).ToList().First()
+ test <@ fromDb.Age = None @>
+
[]
member this.``We can integrate serialize & deserialize on DimmerSwitches``() =
let collection = db.GetCollection "objects"
@@ -197,9 +215,9 @@ type ``When serializing lists``() =
obj.Kitchen <- Off
obj.Bedroom1 <- Dim 42
obj.Bedroom2 <- DimMarquee(12, "when I was little...")
- collection.Save obj |> ignore
+ collection.InsertOne obj
- let fromDb = collection.FindOneById obj.Id
+ let fromDb = collection.Find(fun x -> x.Id = obj.Id).ToList().First()
match fromDb.Kitchen with
| Off -> ()
| _ -> fail "Kitchen light wasn't off"
@@ -210,4 +228,24 @@ type ``When serializing lists``() =
match fromDb.Bedroom2 with
| DimMarquee(12, "when I was little...") -> ()
- | _ -> fail "Bedroom2 doesn't have the party we thought"
\ No newline at end of file
+ | _ -> fail "Bedroom2 doesn't have the party we thought"
+
+ []
+ member _.``It can serialize record with list`` () =
+ let collection = db.GetCollection "objects"
+ let obj = {
+ Id = newBsonObjectId()
+ IntVal = 123
+ DoubleVal = 1.23
+ ListVal = [1;2;3]
+ OptionVal = Some 123
+ }
+ collection.InsertOne obj
+
+ let testCollection = db.GetCollection "objects"
+ output.WriteLine((testCollection |> findById obj.Id).ToJson())
+
+ let fromDb = collection.Find(fun x -> x.Id = obj.Id).ToList().First()
+
+ test <@ obj = fromDb @>
+
diff --git a/MongoDB.FSharp.Tests/MongoDB.FSharp.Tests.fsproj b/MongoDB.FSharp.Tests/MongoDB.FSharp.Tests.fsproj
index a7bf890..f7666e5 100644
--- a/MongoDB.FSharp.Tests/MongoDB.FSharp.Tests.fsproj
+++ b/MongoDB.FSharp.Tests/MongoDB.FSharp.Tests.fsproj
@@ -1,113 +1,23 @@
-
-
+
- Debug
- AnyCPU
- 2.0
de725dac-c637-4da7-a30d-69061d33d1b2
Library
MongoDB.FSharp.Tests
MongoDB.FSharp.Tests
- v4.5
+ net6.0
MongoDB.FSharp.Tests
-
- ..\
- true
- 4.3.0.0
- 56fd75cc
+ true
-
- true
- full
- false
- false
- bin\Debug\
- DEBUG;TRACE
- 3
- bin\Debug\MongoDB.FSharp.Tests.XML
-
-
- pdbonly
- true
- true
- bin\Release\
- TRACE
- 3
- bin\Release\MongoDB.FSharp.Tests.XML
-
-
- 11
-
-
-
-
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
-
-
-
-
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
-
-
-
-
-
-
-
- This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
+
-
-
+
-
- True
-
-
- ..\packages\mongocsharpdriver.1.8.1\lib\net35\MongoDB.Bson.dll
- True
-
-
- ..\packages\mongocsharpdriver.1.8.1\lib\net35\MongoDB.Driver.dll
- True
-
-
-
-
-
- ..\packages\Unquote.3.0.0\lib\net45\Unquote.dll
- True
-
-
- ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll
- True
-
-
- ..\packages\xunit.assert.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll
- True
-
-
- ..\packages\xunit.extensibility.core.2.0.0\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll
- True
-
-
- MongoDB.FSharp
- {7cbeb93a-1590-42db-9e40-61630e79304a}
- True
-
+
-
+
\ No newline at end of file
diff --git a/MongoDB.FSharp.Tests/SerializersTests.fs b/MongoDB.FSharp.Tests/SerializersTests.fs
deleted file mode 100644
index 1a12b2e..0000000
--- a/MongoDB.FSharp.Tests/SerializersTests.fs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace SerializersTests
-
-open Xunit
-
-open MongoDB.FSharp.Serializers
-open TestUtils
-
-
-type ``When registering classes``() =
-
- let stubbed = getClassMap (fun t -> false)
-
- []
- member this.``It sets serialization options``() =
- let classMap = stubbed typeof>
- match classMap with
- | Some cm -> ()
- | None -> fail "expected a classmap"
diff --git a/MongoDB.FSharp.Tests/TestTypes.fs b/MongoDB.FSharp.Tests/TestTypes.fs
new file mode 100644
index 0000000..868fee5
--- /dev/null
+++ b/MongoDB.FSharp.Tests/TestTypes.fs
@@ -0,0 +1,8 @@
+namespace ``Acceptance Tests``
+
+open MongoDB.Bson
+open TestUtils
+
+type ObjectWithOptions() =
+ member val Id : BsonObjectId = newBsonObjectId() with get, set
+ member val Age : int option = None with get, set
diff --git a/MongoDB.FSharp.Tests/TestUtils.fs b/MongoDB.FSharp.Tests/TestUtils.fs
index faab238..9b3eea8 100644
--- a/MongoDB.FSharp.Tests/TestUtils.fs
+++ b/MongoDB.FSharp.Tests/TestUtils.fs
@@ -1,6 +1,14 @@
module TestUtils
+open MongoDB.Bson
+open MongoDB.Driver
open Xunit
let fail msg =
- Assert.True(false, msg)
\ No newline at end of file
+ Assert.True(false, msg)
+
+let newBsonObjectId() = ObjectId.GenerateNewId() |> BsonObjectId
+
+let findById id (collection: IMongoCollection) =
+ let filter = FilterDefinition.op_Implicit(BsonDocument("_id", id))
+ collection.Find(filter).ToList() |> Seq.head
\ No newline at end of file
diff --git a/MongoDB.FSharp.Tests/packages.config b/MongoDB.FSharp.Tests/packages.config
deleted file mode 100644
index 0f28616..0000000
--- a/MongoDB.FSharp.Tests/packages.config
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/MongoDB.FSharp.Tests/paket.references b/MongoDB.FSharp.Tests/paket.references
new file mode 100644
index 0000000..111f5fa
--- /dev/null
+++ b/MongoDB.FSharp.Tests/paket.references
@@ -0,0 +1,6 @@
+FSharp.Core
+xunit
+unquote
+Mongo2Go
+Microsoft.NET.Test.Sdk
+xunit.runner.visualstudio
\ No newline at end of file
diff --git a/MongoDB.FSharp.sln b/MongoDB.FSharp.sln
index 18c1cb6..58adf73 100644
--- a/MongoDB.FSharp.sln
+++ b/MongoDB.FSharp.sln
@@ -3,24 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1207C2F4-D695-48D4-A0D1-9258EC678E22}"
- ProjectSection(SolutionItems) = preProject
- .nuget\NuGet.Config = .nuget\NuGet.Config
- .nuget\NuGet.exe = .nuget\NuGet.exe
- EndProjectSection
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C400BE02-457C-4C0D-BEE1-874EC44EAA22}"
ProjectSection(SolutionItems) = preProject
License.txt = License.txt
MongoDB.FSharp.nuspec = MongoDB.FSharp.nuspec
package.ps1 = package.ps1
README.md = README.md
+ paket.dependencies = paket.dependencies
EndProjectSection
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MongoDB.FSharp", "MongoDB.FSharp\MongoDB.FSharp.fsproj", "{7CBEB93A-1590-42DB-9E40-61630E79304A}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MongoDB.FSharp.Tests", "MongoDB.FSharp.Tests\MongoDB.FSharp.Tests.fsproj", "{DE725DAC-C637-4DA7-A30D-69061D33D1B2}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "MongoDB.FSharp.BackwardCompatTests", "MongoDB.FSharp.BackwardCompatTests\MongoDB.FSharp.BackwardCompatTests.fsproj", "{3D30EBB2-C4B2-4C23-910F-E25FE19E1985}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -35,6 +32,10 @@ Global
{DE725DAC-C637-4DA7-A30D-69061D33D1B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE725DAC-C637-4DA7-A30D-69061D33D1B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE725DAC-C637-4DA7-A30D-69061D33D1B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3D30EBB2-C4B2-4C23-910F-E25FE19E1985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3D30EBB2-C4B2-4C23-910F-E25FE19E1985}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3D30EBB2-C4B2-4C23-910F-E25FE19E1985}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3D30EBB2-C4B2-4C23-910F-E25FE19E1985}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/MongoDB.FSharp/MongoDB.FSharp.fsproj b/MongoDB.FSharp/MongoDB.FSharp.fsproj
index 6b63396..06f124d 100644
--- a/MongoDB.FSharp/MongoDB.FSharp.fsproj
+++ b/MongoDB.FSharp/MongoDB.FSharp.fsproj
@@ -1,83 +1,33 @@
-
-
+
- Debug
- AnyCPU
- 2.0
7cbeb93a-1590-42db-9e40-61630e79304a
Library
MongoDB.FSharp
MongoDB.FSharp
- v4.0
+ net6.0
MongoDB.FSharp
-
- ..\
- true
- 4.3.0.0
+ latest
true
full
- false
- false
bin\Debug\
DEBUG;TRACE
- 3
+ 4
bin\Debug\MongoDB.FSharp.XML
- pdbonly
- true
- true
+ portable
bin\Release\
TRACE
- 3
+ 4
bin\Release\MongoDB.FSharp.XML
+ true
-
- True
-
-
- ..\packages\mongocsharpdriver.1.8.1\lib\net35\MongoDB.Bson.dll
- True
-
-
- ..\packages\mongocsharpdriver.1.8.1\lib\net35\MongoDB.Driver.dll
- True
-
-
-
-
-
-
-
-
-
+
-
- 11
-
-
-
-
- $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets
-
-
-
-
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets
-
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/MongoDB.FSharp/MongoDB.FSharp.fsproj.paket.template b/MongoDB.FSharp/MongoDB.FSharp.fsproj.paket.template
new file mode 100644
index 0000000..9395f7d
--- /dev/null
+++ b/MongoDB.FSharp/MongoDB.FSharp.fsproj.paket.template
@@ -0,0 +1,12 @@
+type project
+id MongoDB.FSharp2
+version 1.0.1
+authors Tim Kellogg, Ruxo Zheng
+owners Tim Kellogg, Ruxo Zheng
+licenseUrl https://github.com/ruxo/MongoDB.FSharp/blob/master/License.txt
+projectUrl https://github.com/ruxo/MongoDB.FSharp
+description
+ F# serializers for MongoDB 2.x.
+ Silent utilities to make the official MongoDB driver feel natural to work with in F#
+requireLicenseAcceptance false
+tags f# fsharp mongodb nosql utility
\ No newline at end of file
diff --git a/MongoDB.FSharp/Script.fsx b/MongoDB.FSharp/Script.fsx
deleted file mode 100644
index 5df4be2..0000000
--- a/MongoDB.FSharp/Script.fsx
+++ /dev/null
@@ -1,13 +0,0 @@
-// This file is a script that can be executed with the F# Interactive.
-// It can be used to explore and test the library project.
-// By default script files are not be part of the project build.
-
-// Learn more about F# at http://fsharp.net. See the 'F# Tutorial' project
-// for more guidance on F# programming.
-
-#load "Library1.fs"
-open MongoDB.FSharp
-
-
-// Define your library scripting code here
-
diff --git a/MongoDB.FSharp/SerializationOptions.fs b/MongoDB.FSharp/SerializationOptions.fs
deleted file mode 100644
index 5b2f41f..0000000
--- a/MongoDB.FSharp/SerializationOptions.fs
+++ /dev/null
@@ -1,50 +0,0 @@
-namespace MongoDB.FSharp
-
-open System
-open MongoDB.Bson
-open MongoDB.Bson.Serialization
-open MongoDB.Bson.Serialization.Options
-open MongoDB.Bson.Serialization.Serializers
-
-module SerializationOptions =
- type System.Object with
- member inline this.GetFriendlyTypeName() =
- this.GetType() |> BsonUtils.GetFriendlyTypeName
-
- type ListSerializationOptions(itemOptions : IBsonSerializationOptions) =
- inherit BsonBaseSerializationOptions()
- let mutable itemSerializatonOptions = itemOptions
- new() = ListSerializationOptions(null)
-
- member val ItemSerializationOptions = itemSerializatonOptions
-
- override this.ApplyAttribute(serializer : IBsonSerializer, attribute : Attribute) =
- this.EnsureNotFrozen()
- let itemSerializer =
- if (serializer :? IBsonArraySerializer) then
- let fmt = sprintf "a serialization options attribute of type %s cannot be used with serializer of type %s."
- let attrType = attribute.GetFriendlyTypeName()
- let serializerType = serializer.GetFriendlyTypeName()
- let msg = fmt attrType serializerType
- raise(NotSupportedException(msg))
-
- (serializer :?> IBsonArraySerializer).GetItemSerializationInfo().Serializer
-
- let ensureSerializationOptions() =
- if itemSerializatonOptions = null then
- let defaultOptions = itemSerializer.GetDefaultSerializationOptions()
- if defaultOptions = null then
- let fmt = sprintf "A serialization options attribute of type %s cannot be used when the serializer is of type %s and the item serializer is of type %s."
- let msg = fmt (attribute.GetFriendlyTypeName()) (serializer.GetFriendlyTypeName())
- raise(NotSupportedException(msg (itemSerializer.GetFriendlyTypeName())))
-
- defaultOptions.Clone()
- else
- itemSerializatonOptions
-
- itemSerializatonOptions <- ensureSerializationOptions()
- itemSerializatonOptions.ApplyAttribute(itemSerializer, attribute)
-
- override this.Clone() =
- ListSerializationOptions(itemSerializatonOptions) :> IBsonSerializationOptions
-
diff --git a/MongoDB.FSharp/Serializers.fs b/MongoDB.FSharp/Serializers.fs
index 2932a5d..2e91a39 100644
--- a/MongoDB.FSharp/Serializers.fs
+++ b/MongoDB.FSharp/Serializers.fs
@@ -1,51 +1,67 @@
namespace MongoDB.FSharp
open System
-open System.Reflection
open Microsoft.FSharp.Reflection
open MongoDB.Bson
open MongoDB.Bson.IO
open MongoDB.Bson.Serialization
-open MongoDB.Bson.Serialization.Options
open MongoDB.Bson.Serialization.Serializers
-open SerializationOptions
-
-module Seq =
- let tryHead s =
- if Seq.isEmpty s then
- None
- else
- Some (s |> Seq.head)
-
module Serializers =
- type MongoDB.Bson.IO.BsonWriter with
- member inline this.WriteEmptyArray() =
- this.WriteStartArray()
- this.WriteEndArray()
-
+ type MongoOptionSerializer<'T>() =
+ inherit SerializerBase<'T option>()
+
+ let contentSerializer = BsonSerializer.LookupSerializer(typeof<'T>)
+
+ override my.Serialize(context, _, value) =
+ let writer = context.Writer
+ match value with
+ | Some v -> contentSerializer.Serialize(context, v)
+ | None -> writer.WriteNull()
+ ()
+
+ override my.Deserialize(context, _) =
+ let reader = context.Reader
+ let savePos = reader.GetBookmark()
+ let readDefined() =
+ if reader.CurrentBsonType = BsonType.Undefined
+ then None
+ else Some (contentSerializer.Deserialize(context) :?> 'T)
+
+ match reader.CurrentBsonType with
+ | BsonType.Null ->
+ reader.ReadNull()
+ None
+ | BsonType.Document ->
+ reader.ReadStartDocument()
+ if reader.FindElement("_v") then
+ reader.ReadStartArray()
+ let result = readDefined()
+ if result.IsNone then reader.ReadUndefined()
+ reader.ReadEndArray()
+ reader.ReadEndDocument()
+ result
+ else
+ if reader.CurrentBsonType = BsonType.EndOfDocument
+ then reader.ReadEndDocument()
+ else reader.ReturnToBookmark(savePos)
+ None
+ | _ -> readDefined()
+
type ListSerializer<'T>() =
- inherit MongoDB.Bson.Serialization.Serializers.BsonBaseSerializer(ListSerializationOptions())
-
- override this.Serialize(writer : BsonWriter, nominalType : Type, value : Object, options : IBsonSerializationOptions) =
- if value = null then
- // There aren't supposed to be null values in F#
- writer.WriteEmptyArray()
- else
- let actualType = value.GetType()
- this.VerifyTypes(nominalType, actualType, typeof>)
+ inherit SerializerBase>()
- let lst = value :?> list<'T>
- writer.WriteStartArray()
-
- lst |> List.iter (fun x -> BsonSerializer.Serialize (writer,typeof<'T>, x))
+ override this.Serialize(context, _, value) =
+ let writer = context.Writer
+ writer.WriteStartArray()
+
+ value |> List.iter (fun x -> BsonSerializer.Serialize (writer,typeof<'T>, x))
- writer.WriteEndArray()
+ writer.WriteEndArray()
- override this.Deserialize(reader : BsonReader, nominalType : Type, actualType : Type, options : IBsonSerializationOptions) =
- let serializationOptions = this.EnsureSerializationOptions(options)
- let itemOptions = serializationOptions.ItemSerializationOptions
+ override this.Deserialize(context, args) =
+ let reader = context.Reader
let readArray() =
seq {
reader.ReadStartArray()
@@ -53,7 +69,7 @@ module Serializers =
while reader.ReadBsonType() <> BsonType.EndOfDocument do
let actualElementType = convention.GetActualType(reader, typeof<'T>)
let serializer = BsonSerializer.LookupSerializer(actualElementType)
- let element = serializer.Deserialize(reader, typeof<'T>, itemOptions)
+ let element = serializer.Deserialize(context, args)
yield element :?> 'T
reader.ReadEndArray()
}
@@ -62,7 +78,7 @@ module Serializers =
reader.ReadStartDocument()
reader.ReadString("_t") |> ignore
reader.ReadName("_v")
- let value = this.Deserialize(reader, actualType, actualType, options)
+ let value = this.Deserialize(context, args)
reader.ReadEndDocument()
value
@@ -70,19 +86,20 @@ module Serializers =
match bsonType with
| BsonType.Null ->
reader.ReadNull()
- null
- | BsonType.Array -> readArray() |> List.ofSeq :> Object
+ List.empty
+ | BsonType.Array -> readArray() |> List.ofSeq
| BsonType.Document -> readArrayFromObject ()
| _ ->
- let msg = sprintf "Can't deserialize a %s from BsonType %s" actualType.FullName (bsonType.ToString())
- raise(InvalidOperationException(msg))
+ let msg = $"Can't deserialize a %s{args.NominalType.FullName} from BsonType %s{bsonType.ToString()}"
+ raise <| InvalidOperationException(msg)
interface IBsonArraySerializer with
- member this.GetItemSerializationInfo() : BsonSerializationInfo =
+ member this.TryGetItemSerializationInfo(serializationInfo) =
let elementName = null
let nominalType = typeof<'T>
let serializer = BsonSerializer.LookupSerializer nominalType
- BsonSerializationInfo(elementName, serializer, nominalType, null)
+ serializationInfo <- BsonSerializationInfo(elementName, serializer, nominalType)
+ true
let fsharpType (typ : Type) =
@@ -91,65 +108,13 @@ module Serializers =
|> Seq.map(fun t -> t.SourceConstructFlags)
|> Seq.tryHead
- let getClassMap isClassMapRegistered (actualType : Type) =
- let rec getMember (_type : Type) name other =
- let memberInfos = _type.GetMember name
- if not (memberInfos |> Seq.isEmpty) then
- Some(Seq.head memberInfos)
- elif other <> null then
- getMember _type other null
- else
- None
-
- if not (isClassMapRegistered actualType) then
- let genericType = typedefof>.MakeGenericType(actualType)
- let classMap = Activator.CreateInstance(genericType) :?> BsonClassMap
-
- classMap.AutoMap()
-
- // TODO: don't just map properties -> anything public, maybe consider using C#'s conventions to some extent
- actualType.GetProperties()
- |> Seq.where (fun prop ->
- classMap.AllMemberMaps |> Seq.exists (fun mm -> mm.MemberInfo = (prop :> MemberInfo)) |> not
- )
- |> Seq.where (fun prop -> prop.GetGetMethod() <> null)
- |> Seq.iter (fun prop -> classMap.MapMember(prop :> MemberInfo) |> ignore )
-
- // TODO: use conventions
- match getMember actualType "Id" "_id" with
- | Some memberInfo -> classMap.MapIdMember memberInfo |> ignore
- | None -> ()
+ let createClassMapSerializer (type': Type) (classMap: BsonClassMap) =
+ let concreteType = type'.MakeGenericType(classMap.ClassType)
+ let ctor = concreteType.GetConstructor([| typeof |])
+ ctor.Invoke([| classMap |]) :?> IBsonSerializer
- match fsharpType actualType with
- | Some SourceConstructFlags.RecordType ->
- // Map creator function. Requires Mongo >1.8
- match actualType.GetConstructors() |> Seq.sortBy (fun c -> c.GetParameters().Length) |> Seq.tryHead with
- | Some c ->
- let parms = classMap.DeclaredMemberMaps |> Seq.map (fun m -> m.ElementName) |> Array.ofSeq
- classMap.MapConstructor (c, parms) |> ignore
- | None -> ()
- | _ -> ()
-
- classMap.Freeze() |> Some
- else
- None
-
- let ensureClassMapRegistered actualType =
- let fn = BsonClassMap.IsClassMapRegistered
- match getClassMap fn actualType with
- | Some map ->
- map |> BsonClassMap.RegisterClassMap
- Some map
- | None ->
- None
-
- type RecordSerializer(classMap : BsonClassMap) =
- inherit MongoDB.Bson.Serialization.Serializers.BsonBaseSerializer()
-
- let classMapSerializer =
- let typ = typeof.Assembly.GetType("MongoDB.Bson.Serialization.BsonClassMapSerializer")
- let ctor = typ.GetConstructor([ typeof ] |> Seq.toArray)
- ctor.Invoke([ classMap ] |> Seq.cast