├── .gitattributes
├── .gitignore
├── .gitmodules
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── CodeCoverage.runsettings
├── FSharpDriver-2012.sln
├── LICENSE
├── README.md
├── src
├── FSharp.MongoDB.Bson
│ ├── FSharp.MongoDB.Bson.fsproj
│ └── Serialization
│ │ ├── Conventions
│ │ ├── DiscriminatedUnionConvention.fs
│ │ ├── OptionTypeConvention.fs
│ │ └── RecordTypeConvention.fs
│ │ ├── FSharpTypeConventions.fs
│ │ ├── FSharpValueSerializers.fs
│ │ └── Serializers
│ │ ├── DiscriminatedUnionSerializer.fs
│ │ ├── FSharpListSerializer.fs
│ │ ├── FSharpMapSerializer.fs
│ │ ├── FSharpSetSerializer.fs
│ │ └── OptionTypeSerializer.fs
└── FSharp.MongoDB.Driver
│ ├── ExpressibleMongo.fs
│ ├── FSharp.MongoDB.Driver.fsproj
│ ├── FluentMongo.fs
│ ├── MongoBackbone.fs
│ ├── MongoBackboneSettings.fs
│ ├── MongoClient.fs
│ ├── MongoCollection.fs
│ ├── MongoDatabase.fs
│ ├── MongoOperationSettings.fs
│ ├── MongoScope.fs
│ ├── MongoScopeOptions.fs
│ ├── Properties
│ └── AssemblyInfo.fs
│ ├── QuotableMongo.fs
│ └── Quotations
│ ├── HelperPatterns.fs
│ ├── QueryPatterns.fs
│ └── UpdatePatterns.fs
└── tests
├── FSharp.MongoDB.Bson.Tests
├── FSharp.MongoDB.Bson.Tests.fsproj
├── FSharpListSerializationTests.fs
├── FSharpMapSerializationTests.fs
├── FSharpSetSerializationTests.fs
├── FSharpValueSerializationTests.fs
├── app.config
└── packages.config
├── FSharp.MongoDB.Driver.FunctionalTests
├── FSharp.MongoDB.Driver.FunctionalTests.fsproj
├── FluentMongoTests.fs
├── app.config
└── packages.config
└── FSharp.MongoDB.Driver.Tests
├── ExpressibleMongoTests.fs
├── FSharp.MongoDB.Driver.Tests.fsproj
├── MongoBackboneTests.fs
├── QuotableMongoTests.fs
├── TypedQuotableMongoTests.fs
├── app.config
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set default behaviour, in case users don't have core.autocrlf set.
2 | * text=auto
3 |
4 | # Explicitly declare text files we want to always be normalized and converted
5 | # to native line endings on checkout.
6 | *.fs text
7 | *.md text
8 |
9 | *.dll binary
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | [Bb]in/
16 | [Oo]bj/
17 |
18 | # MSTest test Results
19 | [Tt]est[Rr]esult*/
20 | [Bb]uild[Ll]og.*
21 |
22 | *_i.c
23 | *_p.c
24 | *.ilk
25 | *.meta
26 | *.obj
27 | *.pch
28 | *.pdb
29 | *.pgc
30 | *.pgd
31 | *.rsp
32 | *.sbr
33 | *.tlb
34 | *.tli
35 | *.tlh
36 | *.tmp
37 | *.tmp_proj
38 | *.log
39 | *.vspscc
40 | *.vssscc
41 | .builds
42 | *.pidb
43 | *.log
44 | *.scc
45 |
46 | # Visual C++ cache files
47 | ipch/
48 | *.aps
49 | *.ncb
50 | *.opensdf
51 | *.sdf
52 | *.cachefile
53 |
54 | # Visual Studio profiler
55 | *.psess
56 | *.vsp
57 | *.vspx
58 |
59 | # Guidance Automation Toolkit
60 | *.gpState
61 |
62 | # ReSharper is a .NET coding add-in
63 | _ReSharper*/
64 | *.[Rr]e[Ss]harper
65 |
66 | # TeamCity is a build add-in
67 | _TeamCity*
68 |
69 | # DotCover is a Code Coverage Tool
70 | *.dotCover
71 |
72 | # NCrunch
73 | *.ncrunch*
74 | .*crunch*.local.xml
75 |
76 | # Installshield output folder
77 | [Ee]xpress/
78 |
79 | # DocProject is a documentation generator add-in
80 | DocProject/buildhelp/
81 | DocProject/Help/*.HxT
82 | DocProject/Help/*.HxC
83 | DocProject/Help/*.hhc
84 | DocProject/Help/*.hhk
85 | DocProject/Help/*.hhp
86 | DocProject/Help/Html2
87 | DocProject/Help/html
88 |
89 | # Click-Once directory
90 | publish/
91 |
92 | # Publish Web Output
93 | *.Publish.xml
94 | *.pubxml
95 |
96 | # NuGet Packages Directory
97 | packages/
98 |
99 | # Windows Azure Build Output
100 | csx
101 | *.build.csdef
102 |
103 | # Windows Store app package directory
104 | AppPackages/
105 |
106 | # Others
107 | sql/
108 | *.Cache
109 | ClientBin/
110 | [Ss]tyle[Cc]op.*
111 | ~$*
112 | *~
113 | *.dbmdl
114 | *.[Pp]ublish.xml
115 | *.pfx
116 | *.publishsettings
117 |
118 | # RIA/Silverlight projects
119 | Generated_Code/
120 |
121 | # Backup & report files from converting an old project file to a newer
122 | # Visual Studio version. Backup files are not needed, because we have git ;-)
123 | _UpgradeReport_Files/
124 | Backup*/
125 | UpgradeLog*.XML
126 | UpgradeLog*.htm
127 |
128 | # SQL Server files
129 | App_Data/*.mdf
130 | App_Data/*.ldf
131 |
132 | # =========================
133 | # Windows detritus
134 | # =========================
135 |
136 | # Windows image file caches
137 | Thumbs.db
138 | ehthumbs.db
139 |
140 | # Folder config file
141 | Desktop.ini
142 |
143 | # Recycle Bin used on file shares
144 | $RECYCLE.BIN/
145 |
146 | # Mac crap
147 | .DS_Store
148 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/mongo-csharp-driver"]
2 | path = lib/mongo-csharp-driver
3 | url = https://github.com/mongodb/mongo-csharp-driver.git
4 |
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mongodb-labs/mongo-fsharp-driver-prototype/492503958d22ef1c1dc5e6aa0b144e846d36b46d/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config"))
32 |
33 |
34 |
35 |
36 | $(SolutionDir).nuget
37 | packages.config
38 |
39 |
40 |
41 |
42 | $(NuGetToolsPath)\NuGet.exe
43 | @(PackageSource)
44 |
45 | "$(NuGetExePath)"
46 | mono --runtime=v4.0.30319 $(NuGetExePath)
47 |
48 | $(TargetDir.Trim('\\'))
49 |
50 | -RequireConsent
51 | -NonInteractive
52 |
53 |
54 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir "$(SolutionDir) "
55 | $(NuGetCommand) pack "$(ProjectPath)" -Properties Configuration=$(Configuration) $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
56 |
57 |
58 |
59 | RestorePackages;
60 | $(BuildDependsOn);
61 |
62 |
63 |
64 |
65 | $(BuildDependsOn);
66 | BuildPackage;
67 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
95 |
97 |
98 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/CodeCoverage.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | .*\.dll$
14 | .*\.exe$
15 |
16 |
17 | .*CPPUnitTestFramework.*
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ^FSharp\.MongoDB\.Driver\..*
27 | ^FSharp\.MongoDB\.Bson\..*
28 |
29 |
30 |
34 | .*\.CompareTo\(.*
35 | .*\.GetHashCode\(.*
36 |
37 |
38 | ^FSharp\.MongoDB\.Driver\.Tests\..*
39 | ^FSharp\.MongoDB\.Bson\.Tests\..*
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ^System.Diagnostics.DebuggerHiddenAttribute$
48 | ^System.Diagnostics.DebuggerNonUserCodeAttribute$
49 | ^System.Runtime.CompilerServices.CompilerGeneratedAttribute$
50 | ^System.CodeDom.Compiler.GeneratedCodeAttribute$
51 | ^System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute$
52 |
53 |
54 |
55 |
56 |
57 |
58 | .*\\atlmfc\\.*
59 | .*\\vctools\\.*
60 | .*\\public\\sdk\\.*
61 | .*\\microsoft sdks\\.*
62 | .*\\vc\\include\\.*
63 |
64 |
65 |
66 |
67 |
68 |
69 | .*microsoft.*
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | ^B77A5C561934E089$
78 | ^B03F5F7F11D50A3A$
79 | ^31BF3856AD364E35$
80 | ^89845DCD8080CC91$
81 | ^71E9BCE111E9429C$
82 | ^8F50407C4E9E73B6$
83 | ^E361AF139669C375$
84 |
85 |
86 |
87 |
88 |
89 | True
90 | True
91 | True
92 | False
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/FSharpDriver-2012.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.MongoDB.Bson", "src\FSharp.MongoDB.Bson\FSharp.MongoDB.Bson.fsproj", "{3C580B01-B163-4E2D-BD4A-AFA062EF813E}"
5 | EndProject
6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.MongoDB.Driver", "src\FSharp.MongoDB.Driver\FSharp.MongoDB.Driver.fsproj", "{F2F775C4-7C17-4E02-A122-123514FC15C6}"
7 | EndProject
8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.MongoDB.Bson.Tests", "tests\FSharp.MongoDB.Bson.Tests\FSharp.MongoDB.Bson.Tests.fsproj", "{3E2AFA32-3B88-4354-A01D-31513FA9EEF9}"
9 | EndProject
10 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.MongoDB.Driver.Tests", "tests\FSharp.MongoDB.Driver.Tests\FSharp.MongoDB.Driver.Tests.fsproj", "{45DDDBC9-5807-43ED-9CDF-A67067C50969}"
11 | ProjectSection(ProjectDependencies) = postProject
12 | {F2F775C4-7C17-4E02-A122-123514FC15C6} = {F2F775C4-7C17-4E02-A122-123514FC15C6}
13 | EndProjectSection
14 | EndProject
15 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.MongoDB.Driver.FunctionalTests", "tests\FSharp.MongoDB.Driver.FunctionalTests\FSharp.MongoDB.Driver.FunctionalTests.fsproj", "{D0113E25-1D28-448B-B236-501BF8A69C77}"
16 | EndProject
17 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{886191B2-2B52-48F4-BE8F-998ED5370554}"
18 | ProjectSection(SolutionItems) = preProject
19 | .nuget\NuGet.Config = .nuget\NuGet.Config
20 | .nuget\NuGet.exe = .nuget\NuGet.exe
21 | .nuget\NuGet.targets = .nuget\NuGet.targets
22 | EndProjectSection
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Release|Any CPU = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {3C580B01-B163-4E2D-BD4A-AFA062EF813E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {3C580B01-B163-4E2D-BD4A-AFA062EF813E}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {3C580B01-B163-4E2D-BD4A-AFA062EF813E}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {3C580B01-B163-4E2D-BD4A-AFA062EF813E}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {F2F775C4-7C17-4E02-A122-123514FC15C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {F2F775C4-7C17-4E02-A122-123514FC15C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {F2F775C4-7C17-4E02-A122-123514FC15C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {F2F775C4-7C17-4E02-A122-123514FC15C6}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {3E2AFA32-3B88-4354-A01D-31513FA9EEF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {3E2AFA32-3B88-4354-A01D-31513FA9EEF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {3E2AFA32-3B88-4354-A01D-31513FA9EEF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {3E2AFA32-3B88-4354-A01D-31513FA9EEF9}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {45DDDBC9-5807-43ED-9CDF-A67067C50969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {45DDDBC9-5807-43ED-9CDF-A67067C50969}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {45DDDBC9-5807-43ED-9CDF-A67067C50969}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {45DDDBC9-5807-43ED-9CDF-A67067C50969}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {D0113E25-1D28-448B-B236-501BF8A69C77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {D0113E25-1D28-448B-B236-501BF8A69C77}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {D0113E25-1D28-448B-B236-501BF8A69C77}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {D0113E25-1D28-448B-B236-501BF8A69C77}.Release|Any CPU.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | EndGlobal
55 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | Copyright (C) 2013 MongoDB, Inc.
179 |
180 | Licensed under the Apache License, Version 2.0 (the "License");
181 | you may not use this file except in compliance with the License.
182 | You may obtain a copy of the License at
183 |
184 | http://www.apache.org/licenses/LICENSE-2.0
185 |
186 | Unless required by applicable law or agreed to in writing, software
187 | distributed under the License is distributed on an "AS IS" BASIS,
188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189 | See the License for the specific language governing permissions and
190 | limitations under the License.
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MongoDB F# Driver Prototype
2 | ===========================
3 |
4 | This is a prototype MongoDB driver written for F#. The goal of this
5 | driver is to make using MongoDB from F# more natural by defining new
6 | ways to express database/collection operations that are idiomatic to
7 | the language.
8 |
9 | #### Special Notes
10 |
11 | The API and implementation are currently subject to change at any time.
12 | You **must not** use this driver in production, as it is still under
13 | development and is in no way supported by MongoDB, Inc.
14 |
15 | We absolutely encourage you to experiment with it and provide us
16 | feedback on the API, design, and implementation. Bug reports and
17 | suggestions for improvements are welcomed, as are pull requests.
18 |
19 | Dependencies
20 | ------------
21 |
22 | * F# 3.0
23 |
24 | Building
25 | --------
26 |
27 | The F# driver has been developed on top of the refactored [Core .NET
28 | driver](https://github.com/mongodb/mongo-csharp-driver/tree/v2.0).
29 | This new ***Core .Net driver*** is still in development as well, and
30 | hence unavailable on NuGet. Thus, the branch has been setup as a
31 | submodule. This is intended to change in the future.
32 |
33 | git submodule update --init
34 |
35 |
36 |
37 | License
38 | -------
39 |
40 | [Apache v2.0](LICENSE)
41 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/FSharp.MongoDB.Bson.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 3c580b01-b163-4e2d-bd4a-afa062ef813e
9 | Library
10 | FSharp.MongoDB.Bson
11 | FSharp.MongoDB.Bson
12 | v4.5
13 | FSharp.MongoDB.Bson
14 |
15 |
16 | true
17 | full
18 | false
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | 3
23 | bin\Debug\FSharp.MongoDB.Bson.xml
24 |
25 |
26 | pdbonly
27 | true
28 | true
29 | bin\Release\
30 | TRACE
31 | 3
32 | bin\Release\FSharp.MongoDB.Bson.xml
33 |
34 |
35 |
36 | True
37 |
38 |
39 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Bson.dll
40 | True
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | Serialization/Conventions/RecordTypeConvention.fs
50 |
51 |
52 | Serialization/Conventions/DiscriminatedUnionConvention.fs
53 |
54 |
55 | Serialization/Conventions/OptionTypeConvention.fs
56 |
57 |
58 | Serialization/Serializers/DiscriminatedUnionSerializer.fs
59 |
60 |
61 | Serialization/Serializers/FSharpListSerializer.fs
62 |
63 |
64 | Serialization/Serializers/FSharpMapSerializer.fs
65 |
66 |
67 | Serialization/Serializers/FSharpSetSerializer.fs
68 |
69 |
70 | Serialization/Serializers/OptionTypeSerializer.fs
71 |
72 |
73 | Serialization/FSharpTypeConventions.fs
74 |
75 |
76 | Serialization/FSharpValueSerializers.fs
77 |
78 |
79 |
80 | 11
81 |
82 |
83 |
84 |
91 |
92 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Conventions/DiscriminatedUnionConvention.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Conventions
17 |
18 | open System
19 | open System.Reflection
20 |
21 | open System.Linq.Expressions
22 |
23 | open Microsoft.FSharp.Reflection
24 |
25 | open MongoDB.Bson.Serialization
26 | open MongoDB.Bson.Serialization.Conventions
27 |
28 | ///
29 | /// Convention for a discriminated union that maps the constructor and fields.
30 | /// Handles when the overall union type contains non-null union cases,
31 | /// or is a singleton union case.
32 | ///
33 | type DiscriminatedUnionConvention() =
34 | inherit ConventionBase("F# Discriminated Union")
35 |
36 | let get index array = Array.get array index
37 |
38 | let isUnion typ = FSharpType.IsUnion typ
39 |
40 | let makeDelegate (meth : MethodInfo) =
41 | let types = meth.GetParameters() |> Array.map (fun x -> x.ParameterType)
42 | Expression.GetDelegateType([| meth.ReturnType |] |> Array.append types)
43 |
44 | let mapCase (classMap : BsonClassMap) (case : UnionCaseInfo) =
45 | let fields = case.GetFields()
46 | let names = fields |> Array.map (fun x -> x.Name)
47 |
48 | classMap.SetDiscriminatorIsRequired true
49 | classMap.SetDiscriminator case.Name
50 |
51 | // Map constructor
52 | let ctor = FSharpValue.PreComputeUnionConstructorInfo(case)
53 | let del = System.Delegate.CreateDelegate(makeDelegate ctor, ctor)
54 |
55 | classMap.MapCreator(del, names) |> ignore
56 |
57 | // Map members
58 | fields |> Array.iter (fun x -> classMap.MapMember(x) |> ignore)
59 |
60 | interface IClassMapConvention with
61 | member __.Apply classMap =
62 | let typ = classMap.ClassType
63 |
64 | // handles when `typ` is a particular union case
65 | if typ.DeclaringType <> null && isUnion typ.DeclaringType then
66 | FSharpType.GetUnionCases typ
67 | |> Array.find (fun x -> x.Name = typ.Name)
68 | |> mapCase classMap
69 |
70 | // handles when `typ` is a singleton discriminated union
71 | elif isUnion typ && not typ.IsAbstract then
72 | let nested = typ.GetNestedTypes() |> Array.filter isUnion
73 | let props = typ.GetProperties() |> Array.filter (fun x -> isUnion x.PropertyType)
74 |
75 | // should not have any nested types or static properties
76 | if nested.Length = 0 && props.Length = 0 then
77 | FSharpType.GetUnionCases typ |> get 0 |> mapCase classMap
78 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Conventions/OptionTypeConvention.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Conventions
17 |
18 | open Microsoft.FSharp.Reflection
19 |
20 | open MongoDB.Bson.Serialization.Conventions
21 |
22 | ///
23 | /// Convention for option types that writes the value in the Some case
24 | /// and omits the field in the None case.
25 | ///
26 | type OptionTypeConvention() =
27 | inherit ConventionBase("F# Option Type")
28 |
29 | let isOption typ = FSharpType.IsUnion typ && typ.IsGenericType
30 | && typ.GetGenericTypeDefinition() = typedefof<_ option>
31 |
32 | interface IMemberMapConvention with
33 | member __.Apply(memberMap) =
34 | let typ = memberMap.MemberType
35 |
36 | if isOption typ then
37 | memberMap.SetDefaultValue None |> ignore
38 | memberMap.SetIgnoreIfNull true |> ignore
39 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Conventions/RecordTypeConvention.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Conventions
17 |
18 | open Microsoft.FSharp.Reflection
19 |
20 | open MongoDB.Bson.Serialization.Conventions
21 |
22 | ///
23 | /// Convention for a record type that maps the constructor and fields.
24 | ///
25 | type RecordTypeConvention() =
26 | inherit ConventionBase("F# Record Type")
27 |
28 | let isRecord typ = FSharpType.IsRecord typ
29 |
30 | interface IClassMapConvention with
31 | member __.Apply(classMap) =
32 | let typ = classMap.ClassType
33 |
34 | if FSharpType.IsRecord(typ) then
35 | let fields = FSharpType.GetRecordFields(typ)
36 | let names = fields |> Array.map (fun x -> x.Name)
37 | let types = fields |> Array.map (fun x -> x.PropertyType)
38 |
39 | // Map constructor
40 | let ctor = typ.GetConstructor(types)
41 | classMap.MapConstructor(ctor, names) |> ignore
42 |
43 | // Map members
44 | fields |> Array.iter (fun x -> classMap.MapMember(x) |> ignore)
45 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/FSharpTypeConventions.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization
17 |
18 | open MongoDB.Bson.Serialization.Conventions
19 |
20 | open FSharp.MongoDB.Bson.Serialization.Conventions
21 |
22 | []
23 | []
24 | /// Entry point to initialize the F# data type conventions.
25 | module Conventions =
26 |
27 | let mutable private registered = false
28 |
29 | []
30 | /// Registers the conventions for F# data types.
31 | let register() =
32 | if not registered then
33 | registered <- true
34 |
35 | let pack = ConventionPack()
36 |
37 | pack.Add(RecordTypeConvention())
38 | pack.Add(OptionTypeConvention())
39 | pack.Add(DiscriminatedUnionConvention())
40 |
41 | ConventionRegistry.Register("F# Type Conventions", pack, (fun _ -> true))
42 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/FSharpValueSerializers.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization
17 |
18 | open Microsoft.FSharp.Reflection
19 |
20 | open MongoDB.Bson.Serialization
21 |
22 | open FSharp.MongoDB.Bson.Serialization.Serializers
23 |
24 | /// Provides (de)serialization of F# data types.
25 | /// Includes options, lists, maps, sets, records, and discriminated unions.
26 | type FSharpValueSerializationProvider() =
27 |
28 | let isUnion typ = FSharpType.IsUnion typ
29 |
30 | let isOption typ = isUnion typ && typ.IsGenericType
31 | && typ.GetGenericTypeDefinition() = typedefof<_ option>
32 |
33 | let isList typ = isUnion typ && typ.IsGenericType
34 | && typ.GetGenericTypeDefinition() = typedefof<_ list>
35 |
36 | let isMap (typ : System.Type) =
37 | typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof>
38 |
39 | let isSet (typ : System.Type) =
40 | typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof>
41 |
42 | interface IBsonSerializationProvider with
43 | member __.GetSerializer(typ : System.Type) =
44 |
45 | // Check that `typ` is an option type
46 | if isOption typ then
47 | OptionTypeSerializer(typ) :> IBsonSerializer
48 |
49 | // Check that `typ` is a list type
50 | elif isList typ then
51 | typedefof>.MakeGenericType (typ.GetGenericArguments())
52 | |> System.Activator.CreateInstance
53 | :?> IBsonSerializer
54 |
55 | // Check that `typ` is a map type
56 | elif isMap typ then
57 | typedefof>.MakeGenericType (typ.GetGenericArguments())
58 | |> System.Activator.CreateInstance
59 | :?> IBsonSerializer
60 |
61 | // Check that `typ` is a set type
62 | elif isSet typ then
63 | typedefof>.MakeGenericType (typ.GetGenericArguments())
64 | |> System.Activator.CreateInstance
65 | :?> IBsonSerializer
66 |
67 | // Check that `typ` is the overall union type, and not a particular union case
68 | elif isUnion typ && typ.BaseType = typeof then
69 | let nested = typ.GetNestedTypes() |> Array.filter isUnion
70 | let props = typ.GetProperties() |> Array.filter (fun x -> isUnion x.PropertyType)
71 |
72 | // Handles non-singleton discriminated unions
73 | if nested.Length > 0 || props.Length > 0 then
74 | nested |> Array.iter (fun x -> BsonClassMap.LookupClassMap x |> ignore)
75 | DiscriminatedUnionSerializer(typ) :> IBsonSerializer
76 |
77 | // Handles singleton discriminated unions
78 | else
79 | let classMap = BsonClassMap.LookupClassMap typ
80 | BsonClassMapSerializer(classMap) :> IBsonSerializer
81 |
82 | // Otherwise, signal we do not provide serialization for this type
83 | else null
84 |
85 | []
86 | []
87 | ///
88 | /// Entry point to initialize the .
89 | ///
90 | module Serializers =
91 |
92 | let mutable private registered = false
93 |
94 | []
95 | /// Registers the .
96 | let register() =
97 | if not registered then
98 | registered <- true
99 | BsonSerializer.RegisterSerializationProvider(FSharpValueSerializationProvider())
100 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Serializers/DiscriminatedUnionSerializer.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Serializers
17 |
18 | open Microsoft.FSharp.Reflection
19 |
20 | open MongoDB.Bson.Serialization
21 | open MongoDB.Bson.Serialization.Serializers
22 |
23 | ///
24 | /// A serializer for discriminated unions.
25 | /// Handles null union cases.
26 | ///
27 | type DiscriminatedUnionSerializer(typ : System.Type) =
28 | inherit BsonBaseSerializer()
29 |
30 | let isUnion typ = FSharpType.IsUnion typ
31 |
32 | let cases = FSharpType.GetUnionCases(typ) |> Seq.map (fun x -> (x.Name, x)) |> dict
33 |
34 | override __.Serialize(writer, nominalType, value, options) =
35 | let (case, fields) = FSharpValue.GetUnionFields(value, typ)
36 |
37 | writer.WriteStartDocument()
38 |
39 | writer.WriteString("_t", case.Name) // TODO: base element name off convention
40 |
41 | writer.WriteEndDocument()
42 |
43 | override __.Deserialize(reader, nominalType, actualType, options) =
44 | let mark = reader.GetBookmark()
45 |
46 | reader.ReadStartDocument()
47 |
48 | let name = reader.ReadString "_t" // TODO: base element name off convention
49 | let union = cases.[name]
50 |
51 | // determine whether name is a null union case or not
52 | match union.GetFields() with
53 | | [| |] ->
54 | reader.ReadEndDocument()
55 | FSharpValue.MakeUnion(union, [| |])
56 |
57 | | _ ->
58 | let case = typ.GetNestedTypes() |> Array.filter isUnion |> Array.find (fun x -> x.Name = name)
59 |
60 | reader.ReturnToBookmark mark
61 | BsonSerializer.Deserialize(reader, case, options) // defer to the class map
62 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Serializers/FSharpListSerializer.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Serializers
17 |
18 | open System.Collections.Generic
19 |
20 | open MongoDB.Bson.Serialization
21 | open MongoDB.Bson.Serialization.Serializers
22 |
23 | ///
24 | /// A serializer for F# lists.
25 | ///
26 | type FSharpListSerializer<'ElemType>() =
27 | inherit BsonBaseSerializer()
28 |
29 | let serializer = EnumerableSerializer<'ElemType>()
30 |
31 | override __.Serialize(writer, nominalType, value, options) =
32 | serializer.Serialize(writer, typeof>, value, options)
33 |
34 | override __.Deserialize(reader, nominalType, actualType, options) =
35 | // deserialize into `IEnumerable` first, then convert to a list
36 | let res = serializer.Deserialize(reader, typeof>, options)
37 | res |> unbox |> List.ofSeq<'ElemType> |> box
38 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Serializers/FSharpMapSerializer.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Serializers
17 |
18 | open System.Collections.Generic
19 |
20 | open MongoDB.Bson.Serialization
21 | open MongoDB.Bson.Serialization.Serializers
22 |
23 | ///
24 | /// A serializer for F# maps.
25 | ///
26 | type FSharpMapSerializer<'KeyType, 'ValueType when 'KeyType : comparison>() =
27 | inherit BsonBaseSerializer()
28 |
29 | let serializer = DictionarySerializer<'KeyType, 'ValueType>()
30 |
31 | override __.Serialize(writer, nominalType, value, options) =
32 | let dictValue =
33 | value
34 | :?> Map<'KeyType, 'ValueType>
35 | |> Map.toSeq
36 | |> dict
37 |
38 | serializer.Serialize(writer, typeof>, dictValue, options)
39 |
40 | override __.Deserialize(reader, nominalType, actualType, options) =
41 | // deserialize into `IDictionary` first, then convert to a map
42 | serializer.Deserialize(reader, typeof>, options)
43 | :?> IDictionary<'KeyType, 'ValueType>
44 | |> Seq.map (|KeyValue|)
45 | |> Map.ofSeq<'KeyType, 'ValueType>
46 | |> box
47 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Serializers/FSharpSetSerializer.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Serializers
17 |
18 | open System.Collections.Generic
19 |
20 | open MongoDB.Bson.Serialization
21 | open MongoDB.Bson.Serialization.Serializers
22 |
23 | ///
24 | /// A serializer for F# sets.
25 | ///
26 | type FSharpSetSerializer<'ElemType when 'ElemType : comparison>() =
27 | inherit BsonBaseSerializer()
28 |
29 | let serializer = EnumerableSerializer<'ElemType>()
30 |
31 | override __.Serialize(writer, nominalType, value, options) =
32 | serializer.Serialize(writer, typeof>, value, options)
33 |
34 | override __.Deserialize(reader, nominalType, actualType, options) =
35 | // deserialize into `IEnumerable` first, then convert to a set
36 | let res = serializer.Deserialize(reader, typeof>, options)
37 | res |> unbox |> Set.ofSeq<'ElemType> |> box
38 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Bson/Serialization/Serializers/OptionTypeSerializer.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Serialization.Serializers
17 |
18 | open Microsoft.FSharp.Reflection
19 |
20 | open MongoDB.Bson.Serialization
21 | open MongoDB.Bson.Serialization.Serializers
22 |
23 | ///
24 | /// A serializer for option types.
25 | /// Writes the value for the Some case, and null for the None case.
26 | ///
27 | type OptionTypeSerializer(typ : System.Type) =
28 | inherit BsonBaseSerializer()
29 |
30 | let cases = FSharpType.GetUnionCases(typ) |> Seq.map (fun x -> (x.Name, x)) |> dict
31 |
32 | override __.Serialize(writer, nominalType, value, options) =
33 | let value = Some (typ.GetProperty("Value").GetValue(value, [| |]))
34 |
35 | match unbox value with
36 | | Some x -> BsonSerializer.Serialize(writer, x.GetType(), x, options)
37 | | None -> BsonSerializer.Serialize(writer, typeof, null, options)
38 |
39 | override __.Deserialize(reader, nominalType, actualType, options) =
40 | let value = BsonSerializer.Deserialize(reader, typ.GenericTypeArguments.[0], options)
41 |
42 | let (case, args) =
43 | match value with
44 | | null -> (cases.["None"], [| |])
45 | | _ -> (cases.["Some"], [| value |])
46 |
47 | FSharpValue.MakeUnion(case, args)
48 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/FSharp.MongoDB.Driver.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | f2f775c4-7c17-4e02-a122-123514fc15c6
9 | Library
10 | MongoDB.Driver
11 | FSharp.MongoDB.Driver
12 | v4.5
13 | FSharp.MongoDB.Driver
14 | ..\..\
15 | true
16 |
17 |
18 | true
19 | full
20 | false
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | 3
25 | bin\Debug\FSharp.MongoDB.Driver.xml
26 |
27 |
28 | pdbonly
29 | true
30 | true
31 | bin\Release\
32 | TRACE
33 | 3
34 | bin\Release\FSharp.MongoDB.Driver.xml
35 |
36 |
37 |
38 | True
39 |
40 |
41 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Bson.dll
42 | True
43 |
44 |
45 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Driver.Core.dll
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Properties/AssemblyInfo.fs
55 |
56 |
57 | Quotations/HelperPatterns.fs
58 |
59 |
60 | Quotations/QueryPatterns.fs
61 |
62 |
63 | Quotations/UpdatePatterns.fs
64 |
65 |
66 | MongoOperationSettings.fs
67 |
68 |
69 | MongoBackboneSettings.fs
70 |
71 |
72 | MongoBackbone.fs
73 |
74 |
75 | MongoScopeOptions.fs
76 |
77 |
78 | MongoScope.fs
79 |
80 |
81 | MongoCollection.fs
82 |
83 |
84 | FluentMongo.fs
85 |
86 |
87 | MongoDatabase.fs
88 |
89 |
90 | MongoClient.fs
91 |
92 |
93 | QuotableMongo.fs
94 |
95 |
96 | ExpressibleMongo.fs
97 |
98 |
99 |
100 |
101 | FSharp.MongoDB.Bson
102 | {3c580b01-b163-4e2d-bd4a-afa062ef813e}
103 | True
104 |
105 |
106 |
107 | 11
108 |
109 |
110 |
111 |
118 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/FluentMongo.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open MongoDB.Bson
19 |
20 | open MongoDB.Driver.Core
21 | open MongoDB.Driver.Core.Protocol
22 | open MongoDB.Driver.Core.Protocol.Messages
23 |
24 | []
25 | module Fluent =
26 |
27 | open Helpers
28 |
29 | []
30 | []
31 | /// Basic operations on the type.
32 | module Scope =
33 |
34 | ///
35 | /// Returns a new with the specified filter.
36 | ///
37 | let find query scope =
38 | { scope with Query = Some query }
39 |
40 | ///
41 | /// Returns a new with the projection applied.
42 | ///
43 | let fields project scope =
44 | { scope with Project = Some project }
45 |
46 | ///
47 | /// Returns a new with the sort order applied.
48 | ///
49 | let sort order scope =
50 | { scope with Sort = Some order }
51 |
52 | ///
53 | /// Returns a new with the limit applied.
54 | /// Used with the number of documents found, updated, or removed.
55 | ///
56 | let limit n scope =
57 | { scope with Limit = n }
58 |
59 | ///
60 | /// Returns a new with the skip applied.
61 | ///
62 | let skip n scope =
63 | { scope with Skip = n }
64 |
65 | ///
66 | /// Returns a new with the query options applied.
67 | ///
68 | let withQueryOptions options scope =
69 | { scope with QueryOptions = options }
70 |
71 | ///
72 | /// Returns a new with the read preference applied.
73 | ///
74 | let withReadPreference readPref scope =
75 | { scope with ReadPreference = readPref }
76 |
77 | ///
78 | /// Returns a new with the write options applied.
79 | ///
80 | let withWriteOptions options scope =
81 | { scope with WriteOptions = options }
82 |
83 | ///
84 | /// Returns the number of documents satisfying the predicate
85 | /// of the current .
86 | ///
87 | let count (scope : Scope<'DocType>) =
88 | let backbone = scope.Backbone
89 | let db = scope.Database
90 | let clctn = scope.Collection
91 |
92 | let cmd = BsonDocument("count", BsonString(clctn))
93 |
94 | match scope.Query with
95 | | Some x -> cmd.Add("query", x) |> ignore
96 | | None -> ()
97 |
98 | let limit = scope.Limit
99 | let skip = scope.Skip
100 |
101 | cmd.AddRange([ BsonElement("limit", BsonInt32(limit))
102 | BsonElement("skip", BsonInt32(skip)) ]) |> ignore
103 |
104 | backbone.Run db cmd
105 |
106 | ///
107 | /// Removes all of the documents satisfying the predicate
108 | /// of the current .
109 | ///
110 | let remove (scope : Scope<'DocType>) =
111 | let backbone = scope.Backbone
112 | let db = scope.Database
113 | let clctn = scope.Collection
114 |
115 | // Raise error if sort has been specified
116 | if scope.Sort.IsSome then failwith "sort has been specified"
117 |
118 | // Raise error if limit has been specified (as other than 1)
119 | if scope.Limit <> 0 && scope.Limit <> 1 then failwith "limit has been specified"
120 |
121 | // Raise error if skip has been specified
122 | if scope.Skip <> 0 then failwith "skip has been specified"
123 |
124 | let query = makeQueryDoc scope.Query None scope.QueryOptions
125 | if scope.WriteOptions.Isolated then query.Add("$isolated", BsonInt32(1)) |> ignore
126 |
127 | let flags = DeleteFlags.None
128 | let settings = { Operation.DefaultSettings.remove with WriteConcern = Some scope.WriteOptions.WriteConcern }
129 |
130 | backbone.Remove db clctn query flags settings
131 |
132 | ///
133 | /// Removes a single document satisfying the predicate
134 | /// of the current .
135 | ///
136 | let removeOne (scope : Scope<'DocType>) =
137 | let backbone = scope.Backbone
138 | let db = scope.Database
139 | let clctn = scope.Collection
140 |
141 | // Raise error if sort has been specified
142 | if scope.Sort.IsSome then failwith "sort has been specified"
143 |
144 | // Ignore limit
145 |
146 | // Raise error if skip has been specified
147 | if scope.Skip <> 0 then failwith "skip has been specified"
148 |
149 | let query = makeQueryDoc scope.Query None scope.QueryOptions
150 | if scope.WriteOptions.Isolated then query.Add("$isolated", BsonInt32(1)) |> ignore
151 |
152 | let flags = DeleteFlags.Single
153 | let settings = { Operation.DefaultSettings.remove with WriteConcern = Some scope.WriteOptions.WriteConcern }
154 |
155 | backbone.Remove db clctn query flags settings
156 |
157 | ///
158 | /// Updates all of the documents satisfying the predicate
159 | /// of the current
160 | /// according to the supplied update modifiers.
161 | ///
162 | let update update (scope : Scope<'DocType>) =
163 | let backbone = scope.Backbone
164 | let db = scope.Database
165 | let clctn = scope.Collection
166 |
167 | // Raise error if sort has been specified
168 | if scope.Sort.IsSome then failwith "sort has been specified"
169 |
170 | // Raise error if limit has been specified (as other than 1)
171 | if scope.Limit <> 0 && scope.Limit <> 1 then failwith "limit has been specified"
172 |
173 | // Raise error if skip has been specified
174 | if scope.Skip <> 0 then failwith "skip has been specified"
175 |
176 | let query = makeQueryDoc scope.Query None scope.QueryOptions
177 | if scope.WriteOptions.Isolated then query.Add("$isolated", BsonInt32(1)) |> ignore
178 |
179 | let flags = UpdateFlags.Multi
180 | let settings = { Operation.DefaultSettings.update with CheckUpdateDocument = Some true
181 | WriteConcern = Some scope.WriteOptions.WriteConcern }
182 |
183 | backbone.Update db clctn query update flags settings
184 |
185 | ///
186 | /// Updates a single document satisfying the predicate
187 | /// of the current
188 | /// according to the supplied update modifiers.
189 | ///
190 | let updateOne update (scope : Scope<'DocType>) =
191 | let backbone = scope.Backbone
192 | let db = scope.Database
193 | let clctn = scope.Collection
194 |
195 | // Raise error if sort has been specified
196 | if scope.Sort.IsSome then failwith "sort has been specified"
197 |
198 | // Ignore limit
199 |
200 | // Raise error if skip has been specified
201 | if scope.Skip <> 0 then failwith "skip has been specified"
202 |
203 | let query = makeQueryDoc scope.Query None scope.QueryOptions
204 |
205 | let flags = UpdateFlags.None
206 | let settings = { Operation.DefaultSettings.update with CheckUpdateDocument = Some true
207 | WriteConcern = Some scope.WriteOptions.WriteConcern }
208 |
209 | backbone.Update db clctn query update flags settings
210 |
211 | ///
212 | /// Replaces all of the documents satisfying the predicate
213 | /// of the current
214 | /// according to the supplied update modifiers.
215 | ///
216 | let replace update (scope : Scope<'DocType>) =
217 | let backbone = scope.Backbone
218 | let db = scope.Database
219 | let clctn = scope.Collection
220 |
221 | // Raise error if sort has been specified
222 | if scope.Sort.IsSome then failwith "sort has been specified"
223 |
224 | // Raise error if limit has been specified (as other than 1)
225 | if scope.Limit <> 0 && scope.Limit <> 1 then failwith "limit has been specified"
226 |
227 | // Raise error if skip has been specified
228 | if scope.Skip <> 0 then failwith "skip has been specified"
229 |
230 | let query = makeQueryDoc scope.Query None scope.QueryOptions
231 | if scope.WriteOptions.Isolated then query.Add("$isolated", BsonInt32(1)) |> ignore
232 |
233 | let flags = UpdateFlags.Multi
234 | let settings = { Operation.DefaultSettings.update with CheckUpdateDocument = Some false
235 | WriteConcern = Some scope.WriteOptions.WriteConcern }
236 |
237 | backbone.Update db clctn query update flags settings
238 |
239 | ///
240 | /// Replaces a single document satisfying the predicate
241 | /// of the current
242 | /// according to the supplied update modifiers.
243 | ///
244 | let replaceOne update (scope : Scope<'DocType>) =
245 | let backbone = scope.Backbone
246 | let db = scope.Database
247 | let clctn = scope.Collection
248 |
249 | // Raise error if sort has been specified
250 | if scope.Sort.IsSome then failwith "sort has been specified"
251 |
252 | // Ignore limit
253 |
254 | // Raise error if skip has been specified
255 | if scope.Skip <> 0 then failwith "skip has been specified"
256 |
257 | let query = makeQueryDoc scope.Query None scope.QueryOptions
258 |
259 | let flags = UpdateFlags.None
260 | let settings = { Operation.DefaultSettings.update with CheckUpdateDocument = Some false
261 | WriteConcern = Some scope.WriteOptions.WriteConcern }
262 |
263 | backbone.Update db clctn query update flags settings
264 |
265 | ///
266 | /// Returns information about the query plan,
267 | /// as represented by the current .
268 | ///
269 | let explain (scope : Scope<'DocType>) =
270 | let backbone = scope.Backbone
271 | let db = scope.Database
272 | let clctn = scope.Collection
273 |
274 | let query = makeQueryDoc scope.Query scope.Sort scope.QueryOptions
275 |
276 | let project =
277 | match scope.Project with
278 | | Some x -> x
279 | | None -> null
280 |
281 | query.Add("$explain", BsonInt32(1)) |> ignore
282 |
283 | let limit = scope.Limit
284 | let skip = scope.Skip
285 |
286 | let flags = QueryFlags.None
287 | let settings = Operation.DefaultSettings.query
288 |
289 | let res = backbone.Find db clctn query project limit skip flags settings
290 | use iter = res.GetEnumerator()
291 |
292 | if not (iter.MoveNext()) then raise <| MongoOperationException("explain command missing response document")
293 | iter.Current
294 |
295 | ///
296 | /// Performs text search with the specified phrase
297 | /// using the current .
298 | ///
299 | let textSearch text (scope : Scope<'DocType>) =
300 | let backbone = scope.Backbone
301 | let db = scope.Database
302 | let clctn = scope.Collection
303 |
304 | let cmd = makeTextSearchDoc clctn text scope.Query scope.Project scope.Limit { Language = None }
305 |
306 | backbone.Run db cmd
307 |
308 | ///
309 | /// Performs text search with the specified phrase and options
310 | /// using the current .
311 | ///
312 | let textSearchWithOptions text (options : Scope.TextSearchOptions) (scope : Scope<'DocType>) =
313 | let backbone = scope.Backbone
314 | let db = scope.Database
315 | let clctn = scope.Collection
316 |
317 | let cmd = makeTextSearchDoc clctn text scope.Query scope.Project scope.Limit options
318 |
319 | backbone.Run db cmd
320 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoBackbone.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open MongoDB.Bson
19 | open MongoDB.Bson.Serialization
20 |
21 | open MongoDB.Driver.Core
22 | open MongoDB.Driver.Core.Connections
23 | open MongoDB.Driver.Core.Diagnostics
24 | open MongoDB.Driver.Core.Events
25 | open MongoDB.Driver.Core.Operations
26 | open MongoDB.Driver.Core.Protocol.Messages
27 | open MongoDB.Driver.Core.Sessions
28 |
29 | /// The system that handles both database- and collection-level operations
30 | /// on a cluster. Meant to provide a consistent interface for use by
31 | /// and ,
32 | /// rather than have a dependency on the Core .NET driver in those modules too.
33 | type internal MongoBackbone(settings : Backbone.AllSettings) =
34 |
35 | let eventPublisher = EventPublisher()
36 |
37 | // builds up the network stream settings
38 | let networkStreamSettings =
39 | NetworkStreamSettings.Create(fun builder ->
40 | // applies the connect timeout (if specified)
41 | match settings.Stream.ConnectTimeout with
42 | | Some x -> builder.SetConnectTimeout x
43 | | None -> ()
44 |
45 | // applies the read timeout (if specified)
46 | match settings.Stream.ReadTimeout with
47 | | Some x -> builder.SetReadTimeout x
48 | | None -> ()
49 |
50 | // applies the write timeout (if specified)
51 | match settings.Stream.WriteTimeout with
52 | | Some x -> builder.SetWriteTimeout x
53 | | None -> ()
54 |
55 | // applies the TCP receive buffer size (if specified)
56 | match settings.Stream.TcpReceiveBufferSize with
57 | | Some x -> builder.SetTcpReceiveBufferSize x
58 | | None -> ()
59 |
60 | // applies the TCP send buffer size (if specified)
61 | match settings.Stream.TcpSendBufferSize with
62 | | Some x -> builder.SetTcpSendBufferSize x
63 | | None -> ()
64 | )
65 |
66 | // uses default stream connection settings; does not support credentialing
67 | let streamConnectionSettings = StreamConnectionSettings.Defaults
68 |
69 | // builds up the connection pool settings
70 | let connectionPoolSettings =
71 | ConnectionPoolSettings.Create(fun builder ->
72 | // applies the maximum idle time of a connection (if specified)
73 | match settings.ConnectionPool.ConnectionMaxIdleTime with
74 | | Some x -> builder.SetConnectionMaxIdleTime x
75 | | None -> ()
76 |
77 | // applies the maximum life time of a connection (if specified)
78 | match settings.ConnectionPool.ConnectionMaxLifeTime with
79 | | Some x -> builder.SetConnectionMaxLifeTime x
80 | | None -> ()
81 |
82 | // applies the maximum connection pool size (if specified)
83 | match settings.ConnectionPool.MaxSize with
84 | | Some x -> builder.SetMaxSize x
85 | | None -> ()
86 |
87 | // applies the minimum connection pool size (if specified)
88 | match settings.ConnectionPool.MinSize with
89 | | Some x -> builder.SetMinSize x
90 | | None -> ()
91 |
92 | // applies the frequence at which to maintain
93 | // the connection pool size (if specified)
94 | match settings.ConnectionPool.SizeMaintenanceFrequency with
95 | | Some x -> builder.SetSizeMaintenanceFrequency x
96 | | None -> ()
97 |
98 | // applies the maximum size of the wait queue (if specified)
99 | match settings.ConnectionPool.WaitQueueSize with
100 | | Some x -> builder.SetWaitQueueSize x
101 | | None -> ()
102 | )
103 |
104 | // builds up the clusterable server settings
105 | let clusterableServerSettings =
106 | ClusterableServerSettings.Create(fun builder ->
107 | // applies the connect retry frequency (if specified)
108 | match settings.ClusterableServer.ConnectRetryFrequency with
109 | | Some x -> builder.SetConnectRetryFrequency x
110 | | None -> ()
111 |
112 | // applies the heartbeat frequence (if specified)
113 | match settings.ClusterableServer.HeartbeatFrequency with
114 | | Some x -> builder.SetHeartbeatFrequency x
115 | | None -> ()
116 |
117 | // applies the default maximum document size (if specified)
118 | match settings.ClusterableServer.MaxDocumentSizeDefault with
119 | | Some x -> builder.SetMaxDocumentSizeDefault x
120 | | None -> ()
121 |
122 | // applies the default maximum message size (if specified)
123 | match settings.ClusterableServer.MaxMessageSizeDefault with
124 | | Some x -> builder.SetMaxMessageSizeDefault x
125 | | None -> ()
126 | )
127 |
128 | // builds up the cluster settings
129 | let clusterSettings = ClusterSettings.Create(fun builder ->
130 | builder.AddHosts(settings.Hosts) // adds the list of hosts
131 |
132 | // applies the replica set name (if specified)
133 | match settings.ReplicaSet with
134 | | Some x -> builder.SetReplicaSetName x
135 | | None -> ()
136 | )
137 |
138 | // creates all of the factories from their settings
139 | let streamFactory = NetworkStreamFactory(networkStreamSettings, DnsCache())
140 | let connFactory = StreamConnectionFactory(streamConnectionSettings, streamFactory,
141 | eventPublisher)
142 |
143 | let connPoolFactory = ConnectionPoolFactory(connectionPoolSettings, connFactory,
144 | eventPublisher)
145 |
146 | let channelFactory = ConnectionPoolChannelProviderFactory(connPoolFactory,
147 | eventPublisher)
148 |
149 | let nodeFactory = ClusterableServerFactory(clusterableServerSettings, channelFactory,
150 | connFactory, eventPublisher)
151 |
152 | let clusterFactory = ClusterFactory(nodeFactory)
153 | let cluster = clusterFactory.Create(clusterSettings)
154 |
155 | // initializes the cluster
156 | do cluster.Initialize()
157 |
158 | /// A session for use on an entire cluster.
159 | member internal x.Session = new ClusterSession(cluster)
160 |
161 | []
162 | /// Basic operations on the cluster.
163 | module internal Operations =
164 |
165 | []
166 | /// Database-level operations.
167 | module DatabaseOps =
168 |
169 | type MongoBackbone with
170 |
171 | /// Runs a command on the specified database.
172 | /// The database name.
173 | /// The command to execute.
174 | member x.Run db cmd =
175 |
176 | let database = DatabaseNamespace(db)
177 |
178 | let commandOp =
179 | GenericCommandOperation(
180 | Database = database,
181 | Command = cmd,
182 | Session = x.Session)
183 |
184 | commandOp.Execute()
185 |
186 | /// Drops the specified database.
187 | /// The database name
188 | member x.DropDatabase db =
189 |
190 | let cmd = BsonDocument("dropDatabase", BsonInt32(1))
191 | x.Run db cmd
192 |
193 | []
194 | /// Collection-level operations.
195 | module CollectionOps =
196 |
197 | type MongoBackbone with
198 |
199 | /// Drops the specified collection.
200 | /// The database name.
201 | /// The collection name.
202 | member x.DropCollection db clctn =
203 |
204 | let cmd = BsonDocument("drop", BsonString(clctn))
205 | x.Run db cmd
206 |
207 | /// Inserts a batch of documents into the specified collection.
208 | /// The database name.
209 | /// The collection name.
210 | member x.BulkInsert db clctn (docs : seq<'DocType>) flags (settings : Operation.InsertSettings) =
211 |
212 | let collection = CollectionNamespace(db, clctn)
213 |
214 | let insertOp =
215 | InsertOperation(
216 | Collection = collection,
217 | Documents = docs,
218 | DocumentType = typeof<'DocType>,
219 | Flags = flags,
220 | Session = x.Session)
221 |
222 | // applies the reader settings to the operation (if specified)
223 | match settings.ReaderSettings with
224 | | Some x -> insertOp.ReaderSettings <- x
225 | | None -> ()
226 |
227 | // applies the writer settings to the operation (if specified)
228 | match settings.WriterSettings with
229 | | Some x -> insertOp.WriterSettings <- x
230 | | None -> ()
231 |
232 | // applies the write concern to the operation (if specified)
233 | match settings.WriteConcern with
234 | | Some x -> insertOp.WriteConcern <- x
235 | | None -> ()
236 |
237 | // applies whether to assign an _id (if specified)
238 | match settings.AssignIdOnInsert with
239 | | Some x -> insertOp.AssignIdOnInsert <- x
240 | | None -> ()
241 |
242 | // applies whether to check the inserted documents (if specified)
243 | match settings.CheckInsertDocuments with
244 | | Some x -> insertOp.CheckInsertDocuments <- x
245 | | None -> ()
246 |
247 | insertOp.Execute()
248 |
249 | /// Inserts a single document into the specified collection.
250 | /// The database name.
251 | /// The collection name.
252 | member x.Insert db clctn doc flags settings =
253 | let res = x.BulkInsert db clctn [ doc ] flags settings
254 | use iter = res.GetEnumerator()
255 |
256 | if not (iter.MoveNext()) then raise <| MongoOperationException("insert command missing write concern result")
257 | iter.Current
258 |
259 | ///
260 | /// Returns a sequence of 'DocType documents
261 | /// from the specified collection that satisfy the predicate.
262 | ///
263 | /// The database name.
264 | /// The collection name.
265 | member x.Find<'DocType> db clctn query project limit skip flags (settings : Operation.QuerySettings) =
266 |
267 | let collection = CollectionNamespace(db, clctn)
268 |
269 | let queryOp =
270 | QueryOperation<'DocType>(
271 | Collection = collection,
272 | Query = query,
273 | Fields = project,
274 | Limit = limit,
275 | Skip = skip,
276 | Flags = flags,
277 | Session = x.Session)
278 |
279 | // applies the reader settings to the operation (if specified)
280 | match settings.ReaderSettings with
281 | | Some x -> queryOp.ReaderSettings <- x
282 | | None -> ()
283 |
284 | // applies the writer settings to the operation (if specified)
285 | match settings.WriterSettings with
286 | | Some x -> queryOp.WriterSettings <- x
287 | | None -> ()
288 |
289 | // applies the batch size to the operation (if specified)
290 | match settings.BatchSize with
291 | | Some x -> queryOp.BatchSize <- x
292 | | None -> ()
293 |
294 | queryOp :> seq<'DocType>
295 |
296 | ///
297 | /// Updates the documents of the specified collection
298 | /// that satisfy the predicate.
299 | ///
300 | /// The database name.
301 | /// The collection name.
302 | member x.Update db clctn query update flags (settings : Operation.UpdateSettings) =
303 |
304 | let collection = CollectionNamespace(db, clctn)
305 |
306 | let updateOp =
307 | UpdateOperation(
308 | Collection = collection,
309 | Query = query,
310 | Update = update,
311 | Flags = flags,
312 | Session = x.Session)
313 |
314 | // applies the reader settings to the operation (if specified)
315 | match settings.ReaderSettings with
316 | | Some x -> updateOp.ReaderSettings <- x
317 | | None -> ()
318 |
319 | // applies the writer settings to the operation (if specified)
320 | match settings.WriterSettings with
321 | | Some x -> updateOp.WriterSettings <- x
322 | | None -> ()
323 |
324 | // applies the write concern to the operation (if specified)
325 | match settings.WriteConcern with
326 | | Some x -> updateOp.WriteConcern <- x
327 | | None -> ()
328 |
329 | // applies whether to check the update document (if specified)
330 | match settings.CheckUpdateDocument with
331 | | Some x -> updateOp.CheckUpdateDocument <- x
332 | | None -> ()
333 |
334 | updateOp.Execute()
335 |
336 | ///
337 | /// Removes the documents from the specified collection
338 | /// that satisfy the predicate.
339 | ///
340 | /// The database name.
341 | /// The collection name.
342 | member x.Remove db clctn query flags (settings : Operation.RemoveSettings) =
343 |
344 | let collection = CollectionNamespace(db, clctn)
345 |
346 | let removeOp =
347 | RemoveOperation(
348 | Collection = collection,
349 | Query = query,
350 | Flags = flags,
351 | Session = x.Session)
352 |
353 | // applies the reader settings to the operation (if specified)
354 | match settings.ReaderSettings with
355 | | Some x -> removeOp.ReaderSettings <- x
356 | | None -> ()
357 |
358 | // applies the writer settings to the operation (if specified)
359 | match settings.WriterSettings with
360 | | Some x -> removeOp.WriterSettings <- x
361 | | None -> ()
362 |
363 | // applies the write concern to the operation (if specified)
364 | match settings.WriteConcern with
365 | | Some x -> removeOp.WriteConcern <- x
366 | | None -> ()
367 |
368 | removeOp.Execute()
369 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoBackboneSettings.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open System
19 | open System.Net
20 |
21 | []
22 | /// Provides configuration of the .
23 | module Backbone =
24 |
25 | []
26 | /// Settings for the .
27 | type StreamSettings = {
28 | ConnectTimeout : TimeSpan option
29 | ReadTimeout : TimeSpan option
30 | TcpReceiveBufferSize : int option
31 | TcpSendBufferSize : int option
32 | WriteTimeout : TimeSpan option
33 | }
34 |
35 | []
36 | /// Settings for the .
37 | type ConnectionPoolSettings = {
38 | ConnectionMaxIdleTime : TimeSpan option
39 | ConnectionMaxLifeTime : TimeSpan option
40 | MaxSize : int option
41 | MinSize : int option
42 | SizeMaintenanceFrequency : TimeSpan option
43 | WaitQueueSize : int option
44 | }
45 |
46 | []
47 | /// Settings for the .
48 | type ClusterableServerSettings = {
49 | ConnectRetryFrequency : TimeSpan option
50 | HeartbeatFrequency : TimeSpan option
51 | MaxDocumentSizeDefault : int option
52 | MaxMessageSizeDefault : int option
53 | }
54 |
55 | []
56 | /// Combined settings for the .
57 | type AllSettings = {
58 | Stream : StreamSettings
59 | ConnectionPool : ConnectionPoolSettings
60 | ClusterableServer : ClusterableServerSettings
61 | Hosts : DnsEndPoint list
62 | ReplicaSet : string option
63 | }
64 |
65 | []
66 | /// Contains the default settings for the various factories
67 | /// and .
68 | module DefaultSettings =
69 |
70 | /// The default settings.
71 | /// Designed to override defaults for only the specific fields.
72 | let stream = {
73 | StreamSettings.ConnectTimeout = None
74 | StreamSettings.ReadTimeout = None
75 | StreamSettings.TcpReceiveBufferSize = None
76 | StreamSettings.TcpSendBufferSize = None
77 | StreamSettings.WriteTimeout = None
78 | }
79 |
80 | /// The default settings.
81 | /// Designed to override defaults for only the specific fields.
82 | let connectionPool = {
83 | ConnectionPoolSettings.ConnectionMaxIdleTime = None
84 | ConnectionPoolSettings.ConnectionMaxLifeTime = None
85 | ConnectionPoolSettings.MaxSize = None
86 | ConnectionPoolSettings.MinSize = None
87 | ConnectionPoolSettings.SizeMaintenanceFrequency = None
88 | ConnectionPoolSettings.WaitQueueSize = None
89 | }
90 |
91 | /// The default settings.
92 | /// Designed to override defaults for only the specific fields.
93 | let clusterableServer = {
94 | ClusterableServerSettings.ConnectRetryFrequency = None
95 | ClusterableServerSettings.HeartbeatFrequency = None
96 | ClusterableServerSettings.MaxDocumentSizeDefault = None
97 | ClusterableServerSettings.MaxMessageSizeDefault = None
98 | }
99 |
100 | /// The default settings.
101 | /// Uses the default settings of the other factories,
102 | /// and connects to a standalone server on localhost at the default port.
103 | let all = {
104 | AllSettings.Stream = stream
105 | AllSettings.ConnectionPool = connectionPool
106 | AllSettings.ClusterableServer = clusterableServer
107 | AllSettings.Hosts = [ DnsEndPoint("localhost", 27017) ]
108 | AllSettings.ReplicaSet = None
109 | }
110 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoClient.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open System.Net
19 |
20 | open FSharp.MongoDB.Bson.Serialization
21 |
22 | []
23 | /// Represents a client of the cluster.
24 | type IMongoClient =
25 | /// Returns the specified database.
26 | /// The database name.
27 | abstract member GetDatabase : string -> IMongoDatabase
28 |
29 | []
30 | []
31 | /// Provides configuration of the .
32 | module Client =
33 |
34 | []
35 | /// Settings for the .
36 | type Settings = {
37 | Stream : Backbone.StreamSettings
38 | ConnectionPool : Backbone.ConnectionPoolSettings
39 | ClusterableServer : Backbone.ClusterableServerSettings
40 | }
41 |
42 | /// The default settings for the .
43 | let defaultSettings = {
44 | Settings.Stream = Backbone.DefaultSettings.stream
45 | Settings.ConnectionPool = Backbone.DefaultSettings.connectionPool
46 | Settings.ClusterableServer = Backbone.DefaultSettings.clusterableServer
47 | }
48 |
49 | type MongoClient =
50 |
51 | val private backbone : MongoBackbone
52 |
53 | new (?settings0 : Client.Settings) =
54 | let settings = defaultArg settings0 Client.defaultSettings
55 |
56 | MongoClient({ Backbone.DefaultSettings.all with Stream = settings.Stream
57 | ConnectionPool = settings.ConnectionPool
58 | ClusterableServer = settings.ClusterableServer })
59 |
60 | new (hosts : DnsEndPoint list, ?settings0 : Client.Settings) =
61 | let settings = defaultArg settings0 Client.defaultSettings
62 |
63 | MongoClient({ Backbone.DefaultSettings.all with Stream = settings.Stream
64 | ConnectionPool = settings.ConnectionPool
65 | ClusterableServer = settings.ClusterableServer
66 | Hosts = hosts })
67 |
68 | new (replicaSet : string, hosts : DnsEndPoint list, ?settings0 : Client.Settings) =
69 | let settings = defaultArg settings0 Client.defaultSettings
70 |
71 | MongoClient({ Backbone.DefaultSettings.all with Stream = settings.Stream
72 | ConnectionPool = settings.ConnectionPool
73 | ClusterableServer = settings.ClusterableServer
74 | Hosts = hosts
75 | ReplicaSet = Some replicaSet })
76 |
77 | private new (settings : Backbone.AllSettings) =
78 | do Conventions.register()
79 | do Serializers.register()
80 |
81 | { backbone = MongoBackbone(settings) }
82 |
83 | interface IMongoClient with
84 | member x.GetDatabase db = MongoDatabase(x.backbone, db) :> IMongoDatabase
85 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoCollection.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open System.Collections
19 | open System.Collections.Generic
20 |
21 | open MongoDB.Bson
22 | open MongoDB.Bson.Serialization
23 |
24 | open MongoDB.Driver.Core
25 | open MongoDB.Driver.Core.Protocol
26 | open MongoDB.Driver.Core.Protocol.Messages
27 |
28 | []
29 | type IMongoCollection<'DocType> =
30 | inherit IEnumerable<'DocType>
31 |
32 | abstract member Drop : unit -> CommandResult
33 |
34 | abstract member Insert : 'DocType -> WriteConcernResult
35 |
36 | abstract member Find : unit -> Scope<'DocType>
37 |
38 | abstract member Find : 'DocTypeOrExample -> Scope<'DocType>
39 |
40 | abstract member Save : 'DocType -> WriteConcernResult
41 |
42 | type MongoCollection<'DocType> =
43 |
44 | val private backbone : MongoBackbone
45 | val private db : string
46 | val private clctn : string
47 |
48 | internal new (backbone, db, clctn) = {
49 | backbone = backbone
50 | db = db
51 | clctn = clctn
52 | }
53 |
54 | interface IMongoCollection<'DocType> with
55 | member x.Drop () = x.backbone.DropCollection x.db x.clctn
56 |
57 | member x.Insert doc =
58 | let options = Scope.DefaultOptions.writeOptions
59 |
60 | let flags = InsertFlags.None
61 | let settings = { Operation.DefaultSettings.insert with WriteConcern = Some options.WriteConcern }
62 |
63 | x.backbone.Insert x.db x.clctn doc flags settings
64 |
65 | member x.Find () =
66 | (x :> IMongoCollection<'DocType>).Find(BsonDocument())
67 |
68 | member x.Find (query0 : 'DocTypeOrExample) =
69 | let query = (box query0).ToBsonDocument(query0.GetType())
70 |
71 | {
72 | Backbone = x.backbone
73 | Database = x.db
74 | Collection = x.clctn
75 |
76 | Query = Some query
77 | Project = None
78 | Sort = None
79 |
80 | Limit = 0
81 | Skip = 0
82 |
83 | QueryOptions = Scope.DefaultOptions.queryOptions
84 | ReadPreference = ReadPreference.Primary
85 | WriteOptions = Scope.DefaultOptions.writeOptions
86 | }
87 |
88 | member x.Save doc =
89 | let options = Scope.DefaultOptions.writeOptions
90 |
91 | let idProvider =
92 | match BsonSerializer.LookupSerializer(doc.GetType()) with
93 | | :? IBsonIdProvider as x -> x
94 | | _ -> failwithf "could not find id provider for document type %O" <| doc.GetType()
95 |
96 | let id = ref null
97 | let idType = ref null
98 | let idGenerator = ref null
99 |
100 | if idProvider.GetDocumentId(doc, id, idType, idGenerator) then // document has an id
101 | // Perform an upsert
102 | let query = BsonDocument("_id", BsonValue.Create(!id))
103 | let update = doc
104 |
105 | let flags = UpdateFlags.Upsert
106 | let settings = { Operation.DefaultSettings.update with WriteConcern = Some options.WriteConcern }
107 |
108 | x.backbone.Update x.db x.clctn query update flags settings
109 | else // document does not have an id
110 | // Perform an insert
111 | let flags = InsertFlags.None
112 | let settings = { Operation.DefaultSettings.insert with WriteConcern = Some options.WriteConcern
113 | AssignIdOnInsert = Some true}
114 |
115 | x.backbone.Insert x.db x.clctn doc flags settings
116 |
117 | interface IEnumerable<'DocType> with
118 | member x.GetEnumerator() = (x :> IMongoCollection<'DocType>).Find().Get()
119 |
120 | interface IEnumerable with
121 | member x.GetEnumerator() = (x :> IEnumerable<'DocType>).GetEnumerator() :> IEnumerator
122 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoDatabase.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open MongoDB.Bson
19 |
20 | open MongoDB.Driver.Core
21 |
22 | []
23 | /// Represents a database of the cluster.
24 | type IMongoDatabase =
25 | /// Drops the specified database.
26 | abstract member Drop : unit -> CommandResult
27 |
28 | /// Returns the specified collection.
29 | /// The collection name.
30 | /// Returns
31 | abstract member GetCollection : string -> IMongoCollection
32 |
33 | ///
34 | /// Returns the specified collection, parametrized by the generic type.
35 | ///
36 | /// The collection name.
37 | abstract member GetCollection<'DocType> : string -> IMongoCollection<'DocType>
38 |
39 | type internal MongoDatabase =
40 |
41 | val private backbone : MongoBackbone
42 | val private db : string
43 |
44 | internal new (backbone, db) = {
45 | backbone = backbone
46 | db = db
47 | }
48 |
49 | interface IMongoDatabase with
50 | member x.Drop () = x.backbone.DropDatabase x.db
51 |
52 | member x.GetCollection clctn =
53 | (x :> IMongoDatabase).GetCollection clctn
54 |
55 | member x.GetCollection<'DocType> clctn =
56 | MongoCollection<'DocType>(x.backbone, x.db, clctn) :> IMongoCollection<'DocType>
57 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoOperationSettings.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open MongoDB.Bson.IO
19 |
20 | open MongoDB.Driver.Core
21 |
22 | []
23 | /// Provides configuration of the database- and collection-level operations.
24 | module Operation =
25 |
26 | []
27 | /// Settings for the .
28 | type CommandSettings = {
29 | ReaderSettings : BsonBinaryReaderSettings option
30 | WriterSettings : BsonBinaryWriterSettings option
31 | }
32 |
33 | []
34 | /// Settings for the .
35 | type InsertSettings = {
36 | ReaderSettings : BsonBinaryReaderSettings option
37 | WriterSettings : BsonBinaryWriterSettings option
38 | WriteConcern : WriteConcern option
39 | AssignIdOnInsert : bool option
40 | CheckInsertDocuments : bool option
41 | }
42 |
43 | []
44 | /// Settings for the .
45 | type QuerySettings = {
46 | ReaderSettings : BsonBinaryReaderSettings option
47 | WriterSettings : BsonBinaryWriterSettings option
48 | BatchSize : int option
49 | }
50 |
51 | []
52 | /// Settings for the .
53 | type UpdateSettings = {
54 | ReaderSettings : BsonBinaryReaderSettings option
55 | WriterSettings : BsonBinaryWriterSettings option
56 | WriteConcern : WriteConcern option
57 | CheckUpdateDocument : bool option
58 | }
59 |
60 | []
61 | /// Settings for the .
62 | type RemoveSettings = {
63 | ReaderSettings : BsonBinaryReaderSettings option
64 | WriterSettings : BsonBinaryWriterSettings option
65 | WriteConcern : WriteConcern option
66 | }
67 |
68 | []
69 | module DefaultSettings =
70 |
71 | /// The default settings for the .
72 | /// Designed to override defaults for only the specific fields.
73 | let command = {
74 | CommandSettings.ReaderSettings = None
75 | CommandSettings.WriterSettings = None
76 | }
77 |
78 | /// The defaults settings for the .
79 | /// Designed to override defaults for only the specific fields.
80 | let insert = {
81 | InsertSettings.ReaderSettings = None
82 | InsertSettings.WriterSettings = None
83 | InsertSettings.WriteConcern = None
84 | InsertSettings.AssignIdOnInsert = None
85 | InsertSettings.CheckInsertDocuments = None
86 | }
87 |
88 | /// The defaults settings for the .
89 | /// Designed to override defaults for only the specific fields.
90 | let query = {
91 | QuerySettings.ReaderSettings = None
92 | QuerySettings.WriterSettings = None
93 | QuerySettings.BatchSize = None
94 | }
95 |
96 | /// The defaults settings for the .
97 | /// Designed to override defaults for only the specific fields.
98 | let update = {
99 | UpdateSettings.ReaderSettings = None
100 | UpdateSettings.WriterSettings = None
101 | UpdateSettings.WriteConcern = None
102 | UpdateSettings.CheckUpdateDocument = None
103 | }
104 |
105 | /// The defaults settings for the .
106 | /// Designed to override defaults for only the specific fields.
107 | let remove = {
108 | RemoveSettings.ReaderSettings = None
109 | RemoveSettings.WriterSettings = None
110 | RemoveSettings.WriteConcern = None
111 | }
112 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoScope.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open System.Collections
19 | open System.Collections.Generic
20 |
21 | open MongoDB.Bson
22 |
23 | open MongoDB.Driver.Core
24 | open MongoDB.Driver.Core.Protocol
25 | open MongoDB.Driver.Core.Protocol.Messages
26 |
27 | []
28 | module private Helpers =
29 |
30 | // version of BsonDocument.Add that can be chained in a pipeline.
31 | let addElem name value (doc : BsonDocument) =
32 | match value with
33 | | Some x -> doc.Add(name, BsonValue.Create x)
34 | | None -> doc
35 |
36 | // prepares a $query enclosed query document
37 | let makeQueryDoc query sort (options : Scope.QueryOptions) =
38 | match sort with
39 | | None when options = Scope.DefaultOptions.queryOptions ->
40 | match query with
41 | | Some x -> x
42 | | None -> BsonDocument()
43 |
44 | | _ ->
45 | match query with
46 | | Some x ->
47 | BsonDocument("$query", x)
48 | |> addElem "$orderby" sort
49 | |> addElem "$comment" options.Comment
50 | |> addElem "$hint" options.Hint
51 | |> addElem "$maxScan" options.MaxScan
52 | |> addElem "$max" options.Max
53 | |> addElem "$min" options.Min
54 | |> addElem "$snapshot" options.Snapshot
55 |
56 | | None -> failwith "unset query"
57 |
58 | // prepares a text search document
59 | let makeTextSearchDoc clctn text query project limit (options : Scope.TextSearchOptions) =
60 | BsonDocument([ BsonElement("text", BsonString(clctn))
61 | BsonElement("search", BsonString(text))
62 | BsonElement("limit", BsonInt32(limit)) ])
63 | |> addElem "filter" query
64 | |> addElem "project" project
65 | |> addElem "language" options.Language
66 |
67 | /// Represents a view over a particular collection.
68 | /// Immutable structure that is able to be chained with other methods
69 | /// that can invoke operations against the database.
70 | type Scope<'DocType> = private {
71 | Backbone : MongoBackbone
72 | Database : string
73 | Collection : string
74 |
75 | Query : BsonDocument option
76 | Project : BsonDocument option
77 | Sort : BsonDocument option
78 |
79 | Limit : int
80 | Skip : int
81 |
82 | QueryOptions : Scope.QueryOptions
83 | ReadPreference : ReadPreference
84 | WriteOptions : Scope.WriteOptions
85 | } with
86 | /// Executes the find operation with the previously supplied settings.
87 | /// Returns an enumerator for explicit iteration, rather than use in a for loop.
88 | member x.Get (?flags0) = // TODO: change to take a CursorOptions instance
89 | let flags = defaultArg flags0 QueryFlags.None
90 |
91 | let backbone = x.Backbone
92 | let db = x.Database
93 | let clctn = x.Collection
94 |
95 | let query = makeQueryDoc x.Query x.Sort x.QueryOptions
96 |
97 | let project =
98 | match x.Project with
99 | | Some x -> x
100 | | None -> null
101 |
102 | let limit = x.Limit
103 | let skip = x.Skip
104 |
105 | let settings = Operation.DefaultSettings.query
106 |
107 | let cursor = backbone.Find<'DocType> db clctn query project limit skip flags settings
108 | cursor.GetEnumerator()
109 |
110 | interface IEnumerable<'DocType> with
111 | member x.GetEnumerator() = x.Get()
112 |
113 | interface IEnumerable with
114 | member x.GetEnumerator() = (x :> IEnumerable<'DocType>).GetEnumerator() :> IEnumerator
115 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/MongoScopeOptions.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open System.Collections
19 | open System.Collections.Generic
20 |
21 | open MongoDB.Bson
22 | open MongoDB.Bson.Serialization
23 |
24 | open MongoDB.Driver.Core
25 | open MongoDB.Driver.Core.Protocol
26 |
27 | []
28 | []
29 | module Scope =
30 |
31 | type QueryOptions = {
32 | Comment : string option
33 | Hint : BsonDocument option
34 | MaxScan : int option
35 | Max : obj option
36 | Min : obj option
37 | Snapshot : bool option
38 | }
39 |
40 | type WriteOptions = {
41 | Isolated : bool
42 | WriteConcern : WriteConcern
43 | Others : (string * obj) list
44 | }
45 |
46 | type TextSearchOptions = {
47 | Language : string option
48 | }
49 |
50 | []
51 | module DefaultOptions =
52 | let queryOptions = {
53 | Comment = None
54 | Hint = None
55 | MaxScan = None
56 | Max = None
57 | Min = None
58 | Snapshot = None
59 | }
60 |
61 | let writeOptions = {
62 | Isolated = false
63 | WriteConcern = WriteConcern.Acknowledged
64 | Others = []
65 | }
66 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/Properties/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver
17 |
18 | open System.Runtime.CompilerServices
19 |
20 | []
21 |
22 | ()
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/QuotableMongo.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver.Quotations
17 |
18 | open Microsoft.FSharp.Quotations
19 | open Microsoft.FSharp.Quotations.Patterns
20 | open Microsoft.FSharp.Quotations.DerivedPatterns
21 | open Microsoft.FSharp.Reflection
22 |
23 | open MongoDB.Bson
24 |
25 | []
26 | ///
27 | /// Contains definition of bson function to parse quotations.
28 | ///
29 | module Impl =
30 |
31 | let private queryParser = Query.parser
32 |
33 | let private updateParser = Update.parser
34 |
35 | ///
36 | /// Traverses an expression and constructs an equivalent BsonDocument based on it structure.
37 | /// When the quotation has a type signature of 'a -> bool , then it is parsed as a query.
38 | /// When the quotation has a type signature of 'a -> unit list
39 | /// or 'a -> 'a , then it is parsed as an update.
40 | ///
41 | /// The code quotation to traverse.
42 | /// A BsonDocument representing the query or update operation.
43 | let bson (q : Expr<'a -> 'b>) =
44 | match box q with
45 | | :? Expr<'a -> bool> as q ->
46 | match q with
47 | | ExprShape.ShapeLambda (v, body) ->
48 | match queryParser v body with
49 | | Some x -> BsonDocument x
50 | | None -> failwithf "unable to parse query\n%A" body
51 |
52 | | _ -> failwith "expected lambda expression"
53 |
54 | | :? Expr<'a -> unit list> as q ->
55 | match q with
56 | | ExprShape.ShapeLambda (v, List (exprs, _)) ->
57 |
58 | let parse = function
59 | | SetField (var, field, value) when var = v -> updateParser var field value
60 |
61 | | SpecificCall <@ (|>) @> (_, _, [ SpecificCall <@ (|>) @> (_, _, [ Var (var); Let (_, List (values, _), Lambda (_, SpecificCall <@ Update.rename @> _)) ])
62 | Lambda (_, SpecificCall <@ ignore @> _) ]) when var = v ->
63 | let zipTransform expr =
64 | match expr with
65 | | NewTuple ([ String (left); String (right) ]) -> BsonElement(left, BsonString(right))
66 | | _ -> failwith "expected (string * string) tuple"
67 |
68 | Some (BsonElement("$rename", BsonDocument(List.map (unbox >> zipTransform) values)))
69 |
70 | | _ -> failwith "unrecognized pattern"
71 |
72 | let doc = BsonDocument()
73 |
74 | exprs |> Seq.cast
75 | |> Seq.iter (fun q ->
76 | match parse q with
77 | | Some elem ->
78 | if not (doc.Contains elem.Name) then
79 | doc.Add (elem.Name, BsonDocument()) |> ignore
80 |
81 | doc.[elem.Name].AsBsonDocument.AddRange elem.Value.AsBsonDocument |> ignore
82 | | None -> () // TODO: raise exception
83 | )
84 |
85 | doc
86 |
87 | | _ -> failwith "expected lambda expression"
88 |
89 | | :? Expr<'a -> 'a> as q ->
90 | match q with
91 | | ExprShape.ShapeLambda (v, body) ->
92 | // handles the { x with foo = ...; bar = ...; ... } form
93 | //
94 | // NOTE: a special case exists for when the first field
95 | // (in the record type definition) is modified,
96 | // as no Let expression is used because it is the first constructor argument
97 | //
98 | // REVIEW: rename this active pattern to something a bit more meaningful?
99 | // e.g. MakeRecord, UpdateRecord
100 | let rec (|NestedLet|_|) expr =
101 | match expr with
102 | // case for when the first record field is unmodified
103 | | NewRecord (typ, PropertyGet _ :: _) -> None
104 |
105 | // case for when the first record field is modified
106 | | NewRecord (typ, value :: _) ->
107 | let field = FSharpType.GetRecordFields(typ).[0]
108 | Some([ field.Name ], [ value ])
109 |
110 | // case for when multiple record fields are modified
111 | | Let (field, value, NestedLet (restFields, restValues)) ->
112 | Some(field.Name :: restFields, value :: restValues)
113 |
114 | // case for when single (or final in series of lets) is modified
115 | // TODO: verify the field (index) of the record type
116 | | Let (field, value, _) -> Some([ field.Name ], [ value ])
117 | | _ -> None
118 |
119 | match body with
120 | | NestedLet (fields, values) ->
121 | let values = values |> List.filter (fun x -> match x with | PropertyGet _ -> false | _ -> true)
122 | let elems = List.map2 (updateParser v) fields values
123 |
124 | let doc = BsonDocument()
125 |
126 | List.map2 (updateParser v) fields values
127 | |> List.iter (fun x ->
128 | match x with
129 | | Some elem ->
130 | if not (doc.Contains elem.Name) then
131 | doc.Add (elem.Name, BsonDocument()) |> ignore
132 |
133 | doc.[elem.Name].AsBsonDocument.AddRange elem.Value.AsBsonDocument |> ignore
134 | | None -> () // TODO: raise exception
135 | )
136 |
137 | doc
138 |
139 | | _ -> failwith "expected nested let or new record expression"
140 |
141 | | _ -> failwith "expected lambda expression"
142 |
143 | | _ -> failwith "unrecognized expression"
144 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/Quotations/HelperPatterns.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver.Quotations
17 |
18 | open Microsoft.FSharp.Quotations
19 | open Microsoft.FSharp.Quotations.Patterns
20 | open Microsoft.FSharp.Quotations.DerivedPatterns
21 | open Microsoft.FSharp.Reflection
22 |
23 | open MongoDB.Bson
24 |
25 | []
26 | module CustomOps =
27 |
28 | let (?) (doc : BsonDocument) (field : string) =
29 | unbox doc.[field]
30 |
31 | let (?<-) (doc : BsonDocument) (field : string) value =
32 | doc.[field] = unbox value |> ignore
33 |
34 | let (=~) input pattern =
35 | System.Text.RegularExpressions.Regex.IsMatch(input, pattern)
36 |
37 | []
38 | module internal Helpers =
39 |
40 | let inline isGenericTypeDefinedFrom<'a> (typ : System.Type) =
41 | typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<'a>
42 |
43 | let inline isListUnionCase (uci : UnionCaseInfo) =
44 | uci.DeclaringType |> isGenericTypeDefinedFrom>
45 |
46 | let private makeGenericListType typ =
47 | typedefof>.MakeGenericType [| typ |]
48 |
49 | let rec (|List|_|) = function
50 | | NewUnionCase (uci, args) when isListUnionCase uci ->
51 | match args with
52 | | [ Value (head, typ); List (tail, _) ] -> Some (head :: tail, typ)
53 | | [ List (head, typ); List (tail, _) ] -> Some (box head :: tail, makeGenericListType typ)
54 | | [ head; List (tail, _) ] -> Some (box head :: tail, typeof)
55 | | [] -> Some ([], typedefof<_>)
56 | | _ -> None
57 |
58 | | _ -> None
59 |
60 | let (|ValueOrList|_|) = function
61 | | Value (value, typ) -> Some (value, typ)
62 | | List (values, typ) -> Some (box values, makeGenericListType typ)
63 | | _ -> None
64 |
65 | let rec (|GetProperty|_|) = function
66 | | PropertyGet (Some (Var (var)), prop, []) ->
67 | Some (var, prop.Name)
68 |
69 | | PropertyGet (Some (GetProperty (var, subdoc)), prop, []) ->
70 | Some (var, sprintf "%s.%s" subdoc prop.Name)
71 |
72 | | _ -> None
73 |
74 | let rec (|CallDynamic|_|) = function
75 | | SpecificCall <@ (?) @> (_, _, [ Var (var); String (field) ])
76 | | Coerce (CallDynamic (var, field), _) ->
77 | Some (var, field)
78 |
79 | | SpecificCall <@ (?) @> (_, _, [ CallDynamic (var, subdoc); String (field) ])
80 | | SpecificCall <@ (?) @> (_, _, [ GetProperty (var, subdoc); String (field) ]) ->
81 | Some (var, sprintf "%s.%s" subdoc field)
82 |
83 | | _ -> None
84 |
85 | let (|GetField|_|) = function
86 | | CallDynamic (var, field) -> Some (var, field)
87 | | GetProperty (var, field) -> Some (var, field)
88 | | _ -> None
89 |
90 | let (|CallDynamicAssignment|_|) = function
91 | | SpecificCall <@ (?<-) @> (_, _, [ Var (var); String (field); value ]) ->
92 | Some (var, field, value)
93 |
94 | | SpecificCall <@ (?<-) @> (_, _, [ GetField (var, subdoc); String (field); value ]) ->
95 | Some (var, sprintf "%s.%s" subdoc field, value)
96 |
97 | | _ -> None
98 |
99 | let (|SetProperty|_|) = function
100 | | PropertySet (Some (Var (var)), prop, [], value) ->
101 | Some (var, prop.Name, value)
102 |
103 | | PropertySet (Some (GetProperty (var, subdoc)), prop, [], value) ->
104 | Some (var, sprintf "%s.%s" subdoc prop.Name, value)
105 |
106 | | _ -> None
107 |
108 | let (|SetField|_|) = function
109 | | CallDynamicAssignment (var, field, value) -> Some (var, field, value)
110 | | SetProperty (var, field, value) -> Some (var, field, value)
111 | | _ -> None
112 |
113 | let (|InfixOp|_|) op = function
114 | | SpecificCall <@ %op @> (_, _, [ lhs; rhs ]) -> Some (lhs, rhs)
115 | | _ -> None
116 |
117 | let (|CallForwardPipe|_|) = function
118 | | InfixOp <@ (|>) @> (x, f) -> Some (x, f)
119 | | _ -> None
120 |
121 | let (|CallForwardCompose|_|) = function
122 | | InfixOp <@ (>>) @> (x, f) -> Some (x, f)
123 | | _ -> None
124 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/Quotations/QueryPatterns.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver.Quotations
17 |
18 | open Microsoft.FSharp.Quotations
19 | open Microsoft.FSharp.Quotations.Patterns
20 | open Microsoft.FSharp.Quotations.DerivedPatterns
21 | open Microsoft.FSharp.Reflection
22 |
23 | open MongoDB.Bson
24 |
25 | []
26 | module Query =
27 |
28 | let all (x : 'a list) (y : 'a list) : bool = invalidOp "not implemented"
29 |
30 | let in' (x : 'a list) (y : 'a) : bool = invalidOp "not implemented"
31 |
32 | let nin (x : 'a list) (y : 'a) : bool = invalidOp "not implemented"
33 |
34 | let nor (x : bool list) : bool = invalidOp "not implemented"
35 |
36 | let exists x : bool = invalidOp "not implemented"
37 |
38 | let nexists x : bool = invalidOp "not implemented"
39 |
40 | let type' (x : BsonType) y : bool = invalidOp "not implemented"
41 |
42 | let where (x : string) y : bool = invalidOp "not implemented"
43 |
44 | let elemMatch (x : 'a -> bool) (y : 'a list) : bool = invalidOp "not implemented"
45 |
46 | let size (x : int) y : bool = invalidOp "not implemented"
47 |
48 | let private toDoc (elem : BsonElement) = BsonDocument elem
49 |
50 | let rec internal parser v q =
51 | let (|Comparison|_|) op = function
52 | | InfixOp op (GetField (var, field), ValueOrList (value, _)) when var = v ->
53 | Some(field, value)
54 | | _ -> None
55 |
56 | match q with
57 | | Comparison <@ (=) @> (field, value) ->
58 | Some (BsonElement(field, BsonValue.Create value))
59 |
60 | | InfixOp <@ (=) @> (InfixOp <@ (%) @> (GetField (var, field), Int32 (divisor)),
61 | Int32 (remainder)) when var = v ->
62 | Some (BsonElement(field, BsonDocument("$mod", BsonArray([ divisor; remainder ]))))
63 |
64 | | Comparison <@ (<>) @> (field, value) ->
65 | Some (BsonElement(field, BsonDocument("$ne", BsonValue.Create value)))
66 |
67 | | Comparison <@ (>) @> (field, value) ->
68 | Some (BsonElement(field, BsonDocument("$gt", BsonValue.Create value)))
69 |
70 | | Comparison <@ (>=) @> (field, value) ->
71 | Some (BsonElement(field, BsonDocument("$gte", BsonValue.Create value)))
72 |
73 | | Comparison <@ (<) @> (field, value) ->
74 | Some (BsonElement(field, BsonDocument("$lt", BsonValue.Create value)))
75 |
76 | | Comparison <@ (<=) @> (field, value) ->
77 | Some (BsonElement(field, BsonDocument("$lte", BsonValue.Create value)))
78 |
79 | | InfixOp <@ (=~) @> (GetField (var, field), String (pcre)) when var = v ->
80 | let index = pcre.LastIndexOf('/')
81 | let regex = pcre.Substring(1, index - 1)
82 | let options = pcre.Substring(index + 1)
83 | Some (BsonElement(field, BsonDocument([ BsonElement("$regex", BsonString(regex))
84 | BsonElement("$options", BsonString(options)) ])))
85 |
86 | | CallForwardPipe (Var (var), expr) when var = v ->
87 | match expr with
88 | | Let (_, String (js), Lambda (_, SpecificCall <@ where @> _)) ->
89 | Some (BsonElement("$where", BsonString(js)))
90 |
91 | | _ -> None
92 |
93 | | CallForwardPipe (GetField (var, field), expr) when var = v ->
94 | match expr with
95 | | Let (_, List (value, _), Lambda (_, SpecificCall <@ all @> _)) ->
96 | Some (BsonElement(field, BsonDocument("$all", BsonValue.Create value)))
97 |
98 | | Let (_, List (value, _), Lambda (_, SpecificCall <@ in' @> _)) ->
99 | Some (BsonElement(field, BsonDocument("$in", BsonValue.Create value)))
100 |
101 | | Let (_, List (value, _), Lambda (_, SpecificCall <@ nin @> _)) ->
102 | Some (BsonElement(field, BsonDocument("$nin", BsonValue.Create value)))
103 |
104 | | Lambda(_, SpecificCall <@ exists @> _) ->
105 | Some (BsonElement(field, BsonDocument("$exists", BsonBoolean(true))))
106 |
107 | | Lambda(_, SpecificCall <@ nexists @> _) ->
108 | Some (BsonElement(field, BsonDocument("$exists", BsonBoolean(false))))
109 |
110 | | Let (_, Value (value, _), Lambda (_, SpecificCall <@ type' @> _)) ->
111 | let typ = value :?> BsonType
112 | Some (BsonElement(field, BsonDocument("$type", BsonValue.Create typ)))
113 |
114 | | Let (_, Lambda (v, q), Lambda (_, SpecificCall <@ elemMatch @> _)) ->
115 | match parser v q with
116 | | Some elem ->
117 | let doc =
118 | if elem.Name = "$and" then // { $and: [ cond1; cond2; ... ] } -> { cond1, cond2, ... }
119 | elem.Value.AsBsonArray.Values
120 | |> Seq.cast
121 | |> Seq.map (fun (x : BsonDocument) -> x.GetElement 0)
122 | |> (fun x -> BsonDocument x)
123 |
124 | else toDoc elem
125 |
126 | Some (BsonElement(field, BsonDocument("$elemMatch", doc)))
127 |
128 | | None -> None
129 |
130 | | Let (_, Int32 (value), Lambda(_, SpecificCall <@ size @> _)) ->
131 | Some (BsonElement(field, BsonDocument("$size", BsonInt32(value))))
132 |
133 | | _ -> None
134 |
135 | | SpecificCall <@ nor @> (_, _, [ List (exprs, _) ]) ->
136 | let elems = exprs |> Seq.cast
137 | |> Seq.fold (fun res q ->
138 | match res with
139 | | Some tail ->
140 | match parser v q with
141 | | Some elem -> Some (toDoc elem :: tail)
142 | | None -> None
143 | | None -> None) (Some [])
144 | |> Option.map List.rev
145 |
146 | match elems with
147 | | Some x -> Some (BsonElement("$nor", BsonArray(x)))
148 | | None -> None
149 |
150 | | SpecificCall <@ not @> (_, _, [ expr ]) ->
151 | match parser v expr with
152 | | Some elem ->
153 | elem.Value <- BsonDocument("$not", elem.Value)
154 | Some elem
155 | | None -> None
156 |
157 | | AndAlso (lhs, rhs) ->
158 | match parser v lhs with
159 | | Some lhsElem ->
160 | match parser v rhs with
161 | | Some rhsElem ->
162 | if lhsElem.Name = "$and" then
163 | lhsElem.Value.AsBsonArray.Add(toDoc rhsElem) |> ignore
164 | Some lhsElem
165 |
166 | else Some (BsonElement("$and", BsonArray([ lhsElem; rhsElem ] |> Seq.map toDoc)))
167 |
168 | | None -> None
169 |
170 | | None -> None
171 |
172 | | OrElse (lhs, rhs) ->
173 | match parser v lhs with
174 | | Some lhsElem ->
175 | match parser v rhs with
176 | | Some rhsElem ->
177 | if lhsElem.Name = "$or" then
178 | lhsElem.Value.AsBsonArray.Add(toDoc rhsElem) |> ignore
179 | Some lhsElem
180 |
181 | else Some (BsonElement("$or", BsonArray([ lhsElem; rhsElem ] |> Seq.map toDoc)))
182 |
183 | | None -> None
184 |
185 | | None -> None
186 |
187 | | _ -> None
188 |
--------------------------------------------------------------------------------
/src/FSharp.MongoDB.Driver/Quotations/UpdatePatterns.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver.Quotations
17 |
18 | open Microsoft.FSharp.Quotations
19 | open Microsoft.FSharp.Quotations.Patterns
20 | open Microsoft.FSharp.Quotations.DerivedPatterns
21 | open Microsoft.FSharp.Reflection
22 |
23 | open MongoDB.Bson
24 |
25 | []
26 | module Update =
27 |
28 | let rename (x : (string * string) list) (y : 'a) : 'a = invalidOp "not implemented"
29 |
30 | let setOnInsert (x : unit list) (y : 'a) : 'a = invalidOp "not implemented"
31 |
32 | let addToSet (x : 'a) (y : 'a list) : 'a list = invalidOp "not implemented"
33 |
34 | let popleft (x : 'a list) : 'a list = invalidOp "not implemented"
35 |
36 | let popright (x : 'a list) : 'a list = invalidOp "not implemented"
37 |
38 | let pull (x : 'a -> bool) (y : 'a list) : 'a list = invalidOp "not implemented"
39 |
40 | let pullAll (x : 'a list) (y : 'a list) : 'a list = invalidOp "not implemented"
41 |
42 | let push (x : 'a) (y : 'a list) : 'a list = invalidOp "not implemented"
43 |
44 | let addToSetEach (x : 'a list) (y : 'a list) : 'a list = invalidOp "not implemented"
45 |
46 | let pushEach (x : 'a list) (y : 'a list) : 'a list = invalidOp "not implemented"
47 |
48 | let slice (x : int) (y : 'a list) : 'a list = invalidOp "not implemented"
49 |
50 | let sortListBy (x : 'a -> 'b) (y : 'a list) : 'a list = invalidOp "not implemented"
51 |
52 | let sortListByDescending (x : 'a -> 'b) (y : 'a list) : 'a list = invalidOp "not implemented"
53 |
54 | let thenListBy (x : 'a -> 'b) (y : 'a list) : 'a list = invalidOp "not implemented"
55 |
56 | let thenListByDescending (x : 'a -> 'b) (y : 'a list) : 'a list = invalidOp "not implemented"
57 |
58 | let private toDoc (elem : BsonElement) = BsonDocument(elem)
59 |
60 | let private queryParser = Query.parser
61 |
62 | let internal parser v field q =
63 | let rec (|DeSugared|_|) v f op = function
64 | | Lambda (_, SpecificCall <@ %op @> _) -> Some []
65 | | Let (_, value, DeSugared v f op (rest)) -> Some (value :: rest)
66 |
67 | | CallForwardPipe (GetField (var, field),
68 | DeSugared v f op (values)) when var = v && field = f ->
69 | Some values
70 |
71 | | InfixOp op (GetField (var, field), value) when var = v && field = f ->
72 | Some [ value ]
73 |
74 | | _ -> None
75 |
76 | let (|PushEach|_|) var field = function
77 | | DeSugared var field <@ pushEach @> ([ List (values, _) ]) ->
78 | let array =
79 | values
80 | |> List.map (fun x ->
81 | try
82 | BsonValue.Create x
83 | with
84 | | :? System.ArgumentException -> x.ToBsonDocument(x.GetType()) :> BsonValue)
85 |
86 | let elem = BsonElement("$push", BsonDocument(field, BsonDocument("$each", BsonArray(array))))
87 | Some elem
88 |
89 | | _ -> None
90 |
91 | let rec (|PushEachWithModifiers|_|) var array = function
92 | | CallForwardPipe (PushEach var array (elem), Let (_, Int32 (value), Lambda (_, SpecificCall <@ slice @> _)))
93 | | CallForwardPipe (PushEachWithModifiers var array (elem), Let (_, Int32 (value), Lambda (_, SpecificCall <@ slice @> _))) ->
94 | elem.Value.[0].AsBsonDocument.Set("$slice", BsonInt32(value)) |> ignore // e.g. { $push: { : { $each ... } }
95 | Some elem
96 |
97 | | CallForwardCompose (PushEach var array (elem), Let (_, Int32(value), Lambda (_, SpecificCall <@ slice @> _)))
98 | | CallForwardCompose (PushEachWithModifiers var array (elem), Let (_, Int32(value), Lambda (_, SpecificCall <@ slice @> _))) ->
99 | elem.Value.[0].AsBsonDocument.Set("$slice", BsonInt32(value)) |> ignore // e.g. { $push: { : { $each ... } }
100 | Some elem
101 |
102 | | CallForwardPipe (PushEach var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListBy @> _)))
103 | | CallForwardPipe (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListBy @> _))) ->
104 | // overwrite, since using last assigned value
105 | elem.Value.[0].AsBsonDocument.Set("$sort", BsonDocument(field, BsonInt32(1))) |> ignore // e.g. { $push: { : { $each ... } }
106 | Some elem
107 |
108 | | CallForwardCompose (PushEach var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListBy @> _)))
109 | | CallForwardCompose (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListBy @> _))) ->
110 | // overwrite, since using last assigned value
111 | elem.Value.[0].AsBsonDocument.Set("$sort", BsonDocument(field, BsonInt32(1))) |> ignore // e.g. { $push: { : { $each ... } }
112 | Some elem
113 |
114 | | CallForwardPipe (PushEach var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListByDescending @> _)))
115 | | CallForwardPipe (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListByDescending @> _))) ->
116 | // overwrite, since using last assigned value
117 | elem.Value.[0].AsBsonDocument.Set("$sort", BsonDocument(field, BsonInt32(-1))) |> ignore // e.g. { $push: { : { $each ... } }
118 | Some elem
119 |
120 | | CallForwardCompose (PushEach var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListByDescending @> _)))
121 | | CallForwardCompose (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ sortListByDescending @> _))) ->
122 | // overwrite, since using last assigned value
123 | elem.Value.[0].AsBsonDocument.Set("$sort", BsonDocument(field, BsonInt32(-1))) |> ignore // e.g. { $push: { : { $each ... } }
124 | Some elem
125 |
126 | | CallForwardPipe (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ thenListBy @> _)))
127 | | CallForwardCompose (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ thenListBy @> _))) ->
128 | // append to $sort document
129 | let sort = elem.Value.[0].AsBsonDocument.GetValue("$sort").AsBsonDocument
130 | // overwrite, since using last assigned value
131 | sort.Set(field, BsonInt32(1)) |> ignore
132 | Some elem
133 |
134 | | CallForwardPipe (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ thenListByDescending @> _)))
135 | | CallForwardCompose (PushEachWithModifiers var array (elem), Let (_, Lambda (_, GetField (_, field)), Lambda (_, SpecificCall <@ thenListByDescending @> _))) ->
136 | // append to $sort document
137 | let sort = elem.Value.[0].AsBsonDocument.GetValue("$sort").AsBsonDocument
138 | // overwrite, since using last assigned value
139 | sort.Set(field, BsonInt32(-1)) |> ignore
140 | Some elem
141 |
142 | | _ -> None
143 |
144 | match q with
145 | | DeSugared v field <@ (+) @> ([ Int32 (value) ]) ->
146 | Some (BsonElement("$inc", BsonDocument(field, BsonInt32(value))))
147 |
148 | | DeSugared v field <@ (-) @> ([ Int32 (value) ]) ->
149 | Some (BsonElement("$inc", BsonDocument(field, BsonInt32(-value))))
150 |
151 | | Value (value, _) ->
152 | Some (BsonElement("$set", BsonDocument(field, BsonValue.Create value)))
153 |
154 | | List (values, _) ->
155 | Some (BsonElement("$set", BsonDocument(field, BsonArray(values))))
156 |
157 | | NewUnionCase (uci, []) when uci.DeclaringType |> isGenericTypeDefinedFrom> ->
158 | Some (BsonElement("$unset", BsonDocument(field, BsonInt32(1))))
159 |
160 | | DeSugared v field <@ addToSet @> ([ Value (value, _) ]) ->
161 | Some (BsonElement("$addToSet", BsonDocument(field, BsonValue.Create value)))
162 |
163 | | DeSugared v field <@ addToSet @> ([ List (values, _) ]) ->
164 | Some (BsonElement("$addToSet", BsonDocument(field, BsonArray(values))))
165 |
166 | | DeSugared v field <@ popleft @> ([]) ->
167 | Some (BsonElement("$pop", BsonDocument(field, BsonInt32(-1))))
168 |
169 | | DeSugared v field <@ popright @> ([]) ->
170 | Some (BsonElement("$pop", BsonDocument(field, BsonInt32(1))))
171 |
172 | | DeSugared v field <@ pull @> ([ Lambda (v, q) ]) ->
173 | match queryParser v q with
174 | | Some elem -> Some (BsonElement("$pull", BsonDocument(field, toDoc elem)))
175 | | None -> None
176 |
177 | | DeSugared v field <@ pullAll @> ([ List (values, _) ]) ->
178 | Some (BsonElement("$pullAll", BsonDocument(field, BsonArray(values))))
179 |
180 | | DeSugared v field <@ push @> ([ Value (value, _) ]) ->
181 | Some (BsonElement("$push", BsonDocument(field, BsonValue.Create value)))
182 |
183 | | DeSugared v field <@ push @> ([ List (values, _) ]) ->
184 | Some (BsonElement("$push", BsonDocument(field, BsonArray(values))))
185 |
186 | | DeSugared v field <@ addToSetEach @> ([ List (values, _) ]) ->
187 | Some (BsonElement("$addToSet", BsonDocument(field, BsonDocument("$each", BsonArray(values)))))
188 |
189 | | PushEach v field (elem) -> Some elem
190 |
191 | | PushEachWithModifiers v field (elem) -> Some elem
192 |
193 | | DeSugared v field <@ (&&&) @> ([ Int32 (value) ]) ->
194 | Some (BsonElement("$bit", BsonDocument(field, BsonDocument("and", BsonInt32(value)))))
195 |
196 | | DeSugared v field <@ (|||) @> ([ Int32 (value) ]) ->
197 | Some (BsonElement("$bit", BsonDocument(field, BsonDocument("or", BsonInt32(value)))))
198 |
199 | | _ -> None
200 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Bson.Tests/FSharp.MongoDB.Bson.Tests.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 3e2afa32-3b88-4354-a01d-31513fa9eef9
9 | Library
10 | FSharp.MongoDB.Bson.Tests
11 | FSharp.MongoDB.Bson.Tests
12 | v4.5
13 | FSharp.MongoDB.Bson.Tests
14 |
15 |
16 | true
17 | full
18 | false
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | 3
23 | bin\Debug\FSharp.MongoDB.Bson.Tests.xml
24 |
25 |
26 | pdbonly
27 | true
28 | true
29 | bin\Release\
30 | TRACE
31 | 3
32 | bin\Release\FSharp.MongoDB.Bson.Tests.xml
33 |
34 |
35 |
36 | True
37 |
38 |
39 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Bson.dll
40 | True
41 |
42 |
43 |
44 | ..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll
45 | True
46 |
47 |
48 |
49 |
50 |
51 | ..\..\packages\Unquote.2.2.2\lib\net40\Unquote.dll
52 | True
53 |
54 |
55 |
56 |
57 | FSharpValueSerializationTests.fs
58 |
59 |
60 | FSharpListSerializationTests.fs
61 |
62 |
63 | FSharpMapSerializationTests.fs
64 |
65 |
66 | FSharpSetSerializationTests.fs
67 |
68 |
69 |
70 |
71 |
72 |
73 | FSharp.MongoDB.Bson
74 | {3c580b01-b163-4e2d-bd4a-afa062ef813e}
75 | True
76 |
77 |
78 |
79 | 11
80 |
81 |
82 |
83 |
90 |
91 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Bson.Tests/FSharpListSerializationTests.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Tests
17 |
18 | open MongoDB.Bson
19 | open MongoDB.Bson.IO
20 | open MongoDB.Bson.Serialization
21 |
22 | open NUnit.Framework
23 | open Swensen.Unquote
24 |
25 | open FSharp.MongoDB.Bson.Serialization
26 |
27 | module FSharpListSerialization =
28 |
29 | do Conventions.register()
30 | do Serializers.register()
31 |
32 | let serialize value =
33 | let doc = BsonDocument()
34 | let writer = new BsonDocumentWriter(doc, BsonDocumentWriterSettings.Defaults)
35 | BsonSerializer.Serialize(writer, value.GetType(), value, null)
36 | doc
37 |
38 | let deserialize doc (typ : System.Type) =
39 | let reader = new BsonDocumentReader(doc, BsonDocumentReaderSettings.Defaults)
40 | unbox (BsonSerializer.Deserialize(reader, typ, null))
41 |
42 | []
43 | module RecordType =
44 |
45 | type Primitive = {
46 | bool : bool list
47 | int : int list
48 | string : string list
49 | float : float list
50 | }
51 |
52 | []
53 | let ``test serialize primitive lists in record type empty``() =
54 | let value = { bool = []
55 | int = []
56 | string = []
57 | float = [] }
58 |
59 | let result = <@ serialize value @>
60 | let expected = <@ BsonDocument([ BsonElement("bool", BsonArray([] : bool list))
61 | BsonElement("int", BsonArray([] : int list))
62 | BsonElement("string", BsonArray([] : string list))
63 | BsonElement("float", BsonArray([] : float list)) ]) @>
64 |
65 | test <@ %result = %expected @>
66 |
67 | []
68 | let ``test deserialize primitive lists in record type empty``() =
69 | let doc = BsonDocument([ BsonElement("bool", BsonArray([] : bool list))
70 | BsonElement("int", BsonArray([] : int list))
71 | BsonElement("string", BsonArray([] : string list))
72 | BsonElement("float", BsonArray([] : float list)) ])
73 |
74 | let result = <@ deserialize doc typeof @>
75 | let expected = <@ { bool = []
76 | int = []
77 | string = []
78 | float = [] } @>
79 |
80 | test <@ %result = %expected @>
81 |
82 | []
83 | let ``test serialize primitive lists in record type singleton``() =
84 | let value = { bool = [ false ]
85 | int = [ 0 ]
86 | string = [ "0.0" ]
87 | float = [ 0.0 ] }
88 |
89 | let result = <@ serialize value @>
90 | let expected = <@ BsonDocument([ BsonElement("bool", BsonArray([ false ]))
91 | BsonElement("int", BsonArray([ 0 ]))
92 | BsonElement("string", BsonArray([ "0.0" ]))
93 | BsonElement("float", BsonArray([ 0.0 ])) ]) @>
94 |
95 | test <@ %result = %expected @>
96 |
97 | []
98 | let ``test deserialize primitive lists in record type singleton``() =
99 | let doc = BsonDocument([ BsonElement("bool", BsonArray([ false ]))
100 | BsonElement("int", BsonArray([ 0 ]))
101 | BsonElement("string", BsonArray([ "0.0" ]))
102 | BsonElement("float", BsonArray([ 0.0 ])) ])
103 |
104 | let result = <@ deserialize doc typeof @>
105 | let expected = <@ { bool = [ false ]
106 | int = [ 0 ]
107 | string = [ "0.0" ]
108 | float = [ 0.0 ] } @>
109 |
110 | test <@ %result = %expected @>
111 |
112 | []
113 | let ``test serialize primitive lists in record type``() =
114 | let value = { bool = [ true; false; false ]
115 | int = [ 1; 0; 0 ]
116 | string = [ "1.0"; "0.0"; "0.0" ]
117 | float = [ 1.0; 0.0; 0.0 ] }
118 |
119 | let result = <@ serialize value @>
120 | let expected = <@ BsonDocument([ BsonElement("bool", BsonArray([ true; false; false ]))
121 | BsonElement("int", BsonArray([ 1; 0; 0 ]))
122 | BsonElement("string", BsonArray([ "1.0"; "0.0"; "0.0" ]))
123 | BsonElement("float", BsonArray([ 1.0; 0.0; 0.0 ])) ]) @>
124 |
125 | test <@ %result = %expected @>
126 |
127 | []
128 | let ``test deserialize primitive lists in record type``() =
129 | let doc = BsonDocument([ BsonElement("bool", BsonArray([ true; false; false ]))
130 | BsonElement("int", BsonArray([ 1; 0; 0 ]))
131 | BsonElement("string", BsonArray([ "1.0"; "0.0"; "0.0" ]))
132 | BsonElement("float", BsonArray([ 1.0; 0.0; 0.0 ])) ])
133 |
134 | let result = <@ deserialize doc typeof @>
135 | let expected = <@ { bool = [ true; false; false ]
136 | int = [ 1; 0; 0 ]
137 | string = [ "1.0"; "0.0"; "0.0" ]
138 | float = [ 1.0; 0.0; 0.0 ] } @>
139 |
140 | test <@ %result = %expected @>
141 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Bson.Tests/FSharpMapSerializationTests.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Tests
17 |
18 | open MongoDB.Bson
19 | open MongoDB.Bson.IO
20 | open MongoDB.Bson.Serialization
21 |
22 | open NUnit.Framework
23 | open Swensen.Unquote
24 |
25 | open FSharp.MongoDB.Bson.Serialization
26 |
27 | module FSharpMapSerialization =
28 |
29 | do Conventions.register()
30 | do Serializers.register()
31 |
32 | let serialize value =
33 | let doc = BsonDocument()
34 | let writer = new BsonDocumentWriter(doc, BsonDocumentWriterSettings.Defaults)
35 | BsonSerializer.Serialize(writer, value.GetType(), value, null)
36 | doc
37 |
38 | let deserialize doc (typ : System.Type) =
39 | let reader = new BsonDocumentReader(doc, BsonDocumentReaderSettings.Defaults)
40 | unbox (BsonSerializer.Deserialize(reader, typ, null))
41 |
42 | []
43 | module RecordType =
44 |
45 | type Primitive = {
46 | bool : Map
47 | int : Map
48 | string : Map
49 | float : Map
50 | }
51 |
52 | []
53 | let ``test serialize primitive maps in record type empty``() =
54 | let value = { bool = [] |> Map.ofList
55 | int = [] |> Map.ofList
56 | string = [] |> Map.ofList
57 | float = [] |> Map.ofList }
58 |
59 | let result = <@ serialize value @>
60 | let expected = <@ BsonDocument([ BsonElement("bool", BsonDocument())
61 | BsonElement("int", BsonDocument())
62 | BsonElement("string", BsonDocument())
63 | BsonElement("float", BsonDocument()) ]) @>
64 |
65 | test <@ %result = %expected @>
66 |
67 | []
68 | let ``test deserialize primitive maps in record type empty``() =
69 | let doc = BsonDocument([ BsonElement("bool", BsonDocument())
70 | BsonElement("int", BsonDocument())
71 | BsonElement("string", BsonDocument())
72 | BsonElement("float", BsonDocument()) ])
73 |
74 | let result = <@ deserialize doc typeof @>
75 | let expected = <@ { bool = [] |> Map.ofList
76 | int = [] |> Map.ofList
77 | string = [] |> Map.ofList
78 | float = [] |> Map.ofList } @>
79 |
80 | test <@ %result = %expected @>
81 |
82 | []
83 | let ``test serialize primitive maps in record type singleton``() =
84 | let value = { bool = [ ("a", false) ] |> Map.ofList
85 | int = [ ("a", 0) ] |> Map.ofList
86 | string = [ ("a", "0.0") ] |> Map.ofList
87 | float = [ ("a", 0.0) ] |> Map.ofList }
88 |
89 | let result = <@ serialize value @>
90 | let expected = <@ BsonDocument([ BsonElement("bool", BsonDocument("a", BsonBoolean(false)))
91 | BsonElement("int", BsonDocument("a", BsonInt32(0)))
92 | BsonElement("string", BsonDocument("a", BsonString("0.0")))
93 | BsonElement("float", BsonDocument("a", BsonDouble(0.0))) ]) @>
94 |
95 | test <@ %result = %expected @>
96 |
97 | []
98 | let ``test deserialize primitive maps in record type singleton``() =
99 | let doc = BsonDocument([ BsonElement("bool", BsonDocument("a", BsonBoolean(false)))
100 | BsonElement("int", BsonDocument("a", BsonInt32(0)))
101 | BsonElement("string", BsonDocument("a", BsonString("0.0")))
102 | BsonElement("float", BsonDocument("a", BsonDouble(0.0))) ])
103 |
104 | let result = <@ deserialize doc typeof @>
105 | let expected = <@ { bool = [ ("a", false) ] |> Map.ofList
106 | int = [ ("a", 0) ] |> Map.ofList
107 | string = [ ("a", "0.0") ] |> Map.ofList
108 | float = [ ("a", 0.0) ] |> Map.ofList } @>
109 |
110 | test <@ %result = %expected @>
111 |
112 | []
113 | let ``test serialize primitive maps in record type``() =
114 | let value = { bool = [ ("b", true); ("a", false); ("c", false) ] |> Map.ofList
115 | int = [ ("b", 1); ("a", 0); ("c", 2) ] |> Map.ofList
116 | string = [ ("b", "1.0"); ("a", "0.0"); ("c", "2.0") ] |> Map.ofList
117 | float = [ ("b", 1.0); ("a", 0.0); ("c", 2.0) ] |> Map.ofList }
118 |
119 | let result = <@ serialize value @>
120 | let expected = <@ BsonDocument([ BsonElement("bool", BsonDocument([ BsonElement("a", BsonBoolean(false))
121 | BsonElement("b", BsonBoolean(true))
122 | BsonElement("c", BsonBoolean(false)) ]))
123 | BsonElement("int", BsonDocument([ BsonElement("a", BsonInt32(0))
124 | BsonElement("b", BsonInt32(1))
125 | BsonElement("c", BsonInt32(2)) ]))
126 | BsonElement("string", BsonDocument([ BsonElement("a", BsonString("0.0"))
127 | BsonElement("b", BsonString("1.0"))
128 | BsonElement("c", BsonString("2.0")) ]))
129 | BsonElement("float", BsonDocument([ BsonElement("a", BsonDouble(0.0))
130 | BsonElement("b", BsonDouble(1.0))
131 | BsonElement("c", BsonDouble(2.0)) ])) ]) @>
132 |
133 | test <@ %result = %expected @>
134 |
135 | []
136 | let ``test deserialize primitive maps in record type``() =
137 | let doc = BsonDocument([ BsonElement("bool", BsonDocument([ BsonElement("a", BsonBoolean(false))
138 | BsonElement("b", BsonBoolean(true))
139 | BsonElement("c", BsonBoolean(false)) ]))
140 | BsonElement("int", BsonDocument([ BsonElement("a", BsonInt32(0))
141 | BsonElement("b", BsonInt32(1))
142 | BsonElement("c", BsonInt32(2)) ]))
143 | BsonElement("string", BsonDocument([ BsonElement("a", BsonString("0.0"))
144 | BsonElement("b", BsonString("1.0"))
145 | BsonElement("c", BsonString("2.0")) ]))
146 | BsonElement("float", BsonDocument([ BsonElement("a", BsonDouble(0.0))
147 | BsonElement("b", BsonDouble(1.0))
148 | BsonElement("c", BsonDouble(2.0)) ])) ])
149 |
150 | let result = <@ deserialize doc typeof @>
151 | let expected = <@ { bool = [ ("b", true); ("a", false); ("c", false) ] |> Map.ofList
152 | int = [ ("b", 1); ("a", 0); ("c", 2) ] |> Map.ofList
153 | string = [ ("b", "1.0"); ("a", "0.0"); ("c", "2.0") ] |> Map.ofList
154 | float = [ ("b", 1.0); ("a", 0.0); ("c", 2.0) ] |> Map.ofList } @>
155 |
156 | test <@ %result = %expected @>
157 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Bson.Tests/FSharpSetSerializationTests.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Bson.Tests
17 |
18 | open MongoDB.Bson
19 | open MongoDB.Bson.IO
20 | open MongoDB.Bson.Serialization
21 |
22 | open NUnit.Framework
23 | open Swensen.Unquote
24 |
25 | open FSharp.MongoDB.Bson.Serialization
26 |
27 | module FSharpSetSerialization =
28 |
29 | do Conventions.register()
30 | do Serializers.register()
31 |
32 | let serialize value =
33 | let doc = BsonDocument()
34 | let writer = new BsonDocumentWriter(doc, BsonDocumentWriterSettings.Defaults)
35 | BsonSerializer.Serialize(writer, value.GetType(), value, null)
36 | doc
37 |
38 | let deserialize doc (typ : System.Type) =
39 | let reader = new BsonDocumentReader(doc, BsonDocumentReaderSettings.Defaults)
40 | unbox (BsonSerializer.Deserialize(reader, typ, null))
41 |
42 | []
43 | module RecordType =
44 |
45 | type Primitive = {
46 | bool : Set
47 | int : Set
48 | string : Set
49 | float : Set
50 | }
51 |
52 | []
53 | let ``test serialize primitive sets in record type empty``() =
54 | let value = { bool = [] |> Set.ofList
55 | int = [] |> Set.ofList
56 | string = [] |> Set.ofList
57 | float = [] |> Set.ofList }
58 |
59 | let result = <@ serialize value @>
60 | let expected = <@ BsonDocument([ BsonElement("bool", BsonArray([] : bool list))
61 | BsonElement("int", BsonArray([] : int list))
62 | BsonElement("string", BsonArray([] : string list))
63 | BsonElement("float", BsonArray([] : float list)) ]) @>
64 |
65 | test <@ %result = %expected @>
66 |
67 | []
68 | let ``test deserialize primitive sets in record type empty``() =
69 | let doc = BsonDocument([ BsonElement("bool", BsonArray([] : bool list))
70 | BsonElement("int", BsonArray([] : int list))
71 | BsonElement("string", BsonArray([] : string list))
72 | BsonElement("float", BsonArray([] : float list)) ])
73 |
74 | let result = <@ deserialize doc typeof @>
75 | let expected = <@ { bool = [] |> Set.ofList
76 | int = [] |> Set.ofList
77 | string = [] |> Set.ofList
78 | float = [] |> Set.ofList } @>
79 |
80 | test <@ %result = %expected @>
81 |
82 | []
83 | let ``test serialize primitive sets in record type singleton``() =
84 | let value = { bool = [ false ] |> Set.ofList
85 | int = [ 0 ] |> Set.ofList
86 | string = [ "0.0" ] |> Set.ofList
87 | float = [ 0.0 ] |> Set.ofList }
88 |
89 | let result = <@ serialize value @>
90 | let expected = <@ BsonDocument([ BsonElement("bool", BsonArray([ false ]))
91 | BsonElement("int", BsonArray([ 0 ]))
92 | BsonElement("string", BsonArray([ "0.0" ]))
93 | BsonElement("float", BsonArray([ 0.0 ])) ]) @>
94 |
95 | test <@ %result = %expected @>
96 |
97 | []
98 | let ``test deserialize primitive sets in record type singleton``() =
99 | let doc = BsonDocument([ BsonElement("bool", BsonArray([ false ]))
100 | BsonElement("int", BsonArray([ 0 ]))
101 | BsonElement("string", BsonArray([ "0.0" ]))
102 | BsonElement("float", BsonArray([ 0.0 ])) ])
103 |
104 | let result = <@ deserialize doc typeof @>
105 | let expected = <@ { bool = [ false ] |> Set.ofList
106 | int = [ 0 ] |> Set.ofList
107 | string = [ "0.0" ] |> Set.ofList
108 | float = [ 0.0 ] |> Set.ofList } @>
109 |
110 | test <@ %result = %expected @>
111 |
112 | []
113 | let ``test serialize primitive sets in record type``() =
114 | let value = { bool = [ true; false; false ] |> Set.ofList
115 | int = [ 1; 0; 2 ] |> Set.ofList
116 | string = [ "1.0"; "0.0"; "2.0" ] |> Set.ofList
117 | float = [ 1.0; 0.0; 2.0 ] |> Set.ofList }
118 |
119 | let result = <@ serialize value @>
120 | let expected = <@ BsonDocument([ BsonElement("bool", BsonArray([ false; true ]))
121 | BsonElement("int", BsonArray([ 0; 1; 2 ]))
122 | BsonElement("string", BsonArray([ "0.0"; "1.0"; "2.0" ]))
123 | BsonElement("float", BsonArray([ 0.0; 1.0; 2.0 ])) ]) @>
124 |
125 | test <@ %result = %expected @>
126 |
127 | []
128 | let ``test deserialize primitive sets in record type``() =
129 | let doc = BsonDocument([ BsonElement("bool", BsonArray([ true; false; false ]))
130 | BsonElement("int", BsonArray([ 1; 0; 2 ]))
131 | BsonElement("string", BsonArray([ "1.0"; "0.0"; "2.0" ]))
132 | BsonElement("float", BsonArray([ 1.0; 0.0; 2.0 ])) ])
133 |
134 | let result = <@ deserialize doc typeof @>
135 | let expected = <@ { bool = [ false; false; true ] |> Set.ofList
136 | int = [ 0; 1; 2 ] |> Set.ofList
137 | string = [ "0.0"; "1.0"; "2.0" ] |> Set.ofList
138 | float = [ 0.0; 1.0; 2.0 ] |> Set.ofList } @>
139 |
140 | test <@ %result = %expected @>
141 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Bson.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Bson.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.FunctionalTests/FSharp.MongoDB.Driver.FunctionalTests.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | d0113e25-1d28-448b-b236-501bf8a69c77
9 | Library
10 | FSharp.MongoDB.Driver.FunctionalTests
11 | FSharp.MongoDB.Driver.FunctionalTests
12 | v4.5
13 | FSharp.MongoDB.Driver.FunctionalTests
14 |
15 |
16 | true
17 | full
18 | false
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | 3
23 | bin\Debug\FSharp.MongoDB.Driver.FunctionalTests.xml
24 |
25 |
26 | pdbonly
27 | true
28 | true
29 | bin\Release\
30 | TRACE
31 | 3
32 | bin\Release\FSharp.MongoDB.Driver.FunctionalTests.xml
33 |
34 |
35 |
36 | True
37 |
38 |
39 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Bson.dll
40 | True
41 |
42 |
43 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Driver.Core.dll
44 | True
45 |
46 |
47 |
48 | ..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll
49 | True
50 |
51 |
52 |
53 |
54 |
55 | ..\..\packages\Unquote.2.2.2\lib\net40\Unquote.dll
56 | True
57 |
58 |
59 |
60 |
61 | FluentMongoTests.fs
62 |
63 |
64 |
65 |
66 |
67 |
68 | FSharp.MongoDB.Driver
69 | {f2f775c4-7c17-4e02-a122-123514fc15c6}
70 | True
71 |
72 |
73 |
74 | 11
75 |
76 |
77 |
84 |
85 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.FunctionalTests/FluentMongoTests.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver.Tests
17 |
18 | open MongoDB.Bson
19 |
20 | open NUnit.Framework
21 | open Swensen.Unquote
22 |
23 | open FSharp.MongoDB.Driver
24 |
25 | module FluentMongo =
26 |
27 | []
28 | module private Configuration =
29 |
30 | let private client = MongoClient() :> IMongoClient
31 |
32 | let private db = "fsharpdriverfunctionaltests"
33 |
34 | let internal database = client.GetDatabase db
35 |
36 | []
37 | module InsertOps =
38 |
39 | let private clctn = "insertops"
40 |
41 | let private collection = database.GetCollection clctn
42 |
43 | []
44 | let ``drop collection``() =
45 | collection.Drop() |> ignore
46 |
47 | []
48 | let ``test fluent api insert``() =
49 | let doc = BsonDocument([ BsonElement("item", BsonString("card"))
50 | BsonElement("qty", BsonInt32(15)) ])
51 |
52 | collection.Insert doc |> ignore
53 |
54 | let res = collection.Find doc |> Seq.toList
55 |
56 | res.Length =? 1 // should only have single document in collection
57 | let found = res.Head
58 |
59 | // Check that found document contains correct values for elements of inserted document
60 | for elem in doc do
61 | test <@ elem.Value = found.[elem.Name] @>
62 |
63 | // Check that found document contains no other fields than previously examined
64 | test <@ doc.ElementCount = found.ElementCount @>
65 |
66 | []
67 | module UpdateOps =
68 |
69 | let private clctn = "updateops"
70 |
71 | let private collection = database.GetCollection clctn
72 |
73 | []
74 | let ``drop collection``() =
75 | collection.Drop() |> ignore
76 |
77 | []
78 | let ``test fluent api update reusing scope``() =
79 | let doc = BsonDocument([ BsonElement("item", BsonString("card"))
80 | BsonElement("qty", BsonInt32(15)) ])
81 |
82 | collection.Insert doc |> ignore
83 |
84 | let scope = collection.Find (BsonDocument("_id", doc.["_id"]))
85 |
86 | let checkInsert (scope : Scope) =
87 | let res = scope |> Seq.toList
88 |
89 | res.Length =? 1 // should only have single document in collection
90 | let found = res.Head
91 |
92 | // Check that found document contains correct values for elements of inserted document
93 | for elem in doc do
94 | test <@ elem.Value = found.[elem.Name] @>
95 |
96 | // Check that found document contains no other fields than previously examined
97 | test <@ doc.ElementCount = found.ElementCount @>
98 |
99 | checkInsert scope
100 |
101 | scope |> Scope.update (BsonDocument("$inc", BsonDocument("qty", BsonInt32(-1)))) |> ignore
102 |
103 | let checkUpdate (scope : Scope) =
104 | let res = scope |> Seq.toList
105 |
106 | res.Length =? 1 // should only have single document in collection
107 | let found = res.Head
108 |
109 | // Check that found document contains correct values for elements of updated document
110 | for elem in doc do
111 | if elem.Name = "qty" then
112 | test <@ elem.Value.AsInt32 - 1 = found.[elem.Name].AsInt32 @>
113 | else
114 | test <@ elem.Value = found.[elem.Name] @>
115 |
116 | checkUpdate scope
117 |
118 | []
119 | module RemoveOps =
120 |
121 | let private clctn = "removeops"
122 |
123 | let private collection = database.GetCollection clctn
124 |
125 | []
126 | let ``drop collection``() =
127 | collection.Drop() |> ignore
128 |
129 | []
130 | let ``test fluent api remove single``() =
131 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
132 | BsonElement("item", BsonString("pencil"));
133 | BsonElement("qty", BsonInt32(50));
134 | BsonElement("type", BsonString("no.2")) ]);
135 | BsonDocument([ BsonElement("item", BsonString("pen"));
136 | BsonElement("qty", BsonInt32(20)) ]);
137 | BsonDocument([ BsonElement("item", BsonString("eraser"));
138 | BsonElement("qty", BsonInt32(25)) ]) ]
139 |
140 | for x in docs do
141 | collection.Insert x |> ignore
142 |
143 | let scope = collection.Find (BsonDocument("_id", BsonInt32(11)))
144 |
145 | let checkInsert (scope : Scope) =
146 | let res = scope |> Seq.toList
147 |
148 | res.Length =? 1 // should only have single document in collection
149 | let found = res.Head
150 |
151 | let doc = docs.[0]
152 |
153 | // Check that found document contains correct values for elements of inserted document
154 | for elem in doc do
155 | test <@ elem.Value = found.[elem.Name] @>
156 |
157 | // Check that found document contains no other fields than previously examined
158 | test <@ doc.ElementCount = found.ElementCount @>
159 |
160 | checkInsert scope
161 |
162 | scope |> Scope.removeOne |> ignore
163 |
164 | let removeQuery = BsonDocument("_id", BsonInt32(11))
165 |
166 | let checkRemove (scope : Scope) =
167 | let res = scope |> Seq.toList
168 |
169 | res.Length =? 0 // should not find any documents
170 |
171 | checkRemove scope
172 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.FunctionalTests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.FunctionalTests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.Tests/FSharp.MongoDB.Driver.Tests.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 45dddbc9-5807-43ed-9cdf-a67067c50969
9 | Library
10 | FSharp.MongoDB.Driver.Tests
11 | FSharp.MongoDB.Driver.Tests
12 | v4.5
13 | FSharp.MongoDB.Driver.Tests
14 | ..\..\
15 | true
16 |
17 |
18 | true
19 | full
20 | false
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | 3
25 | bin\Debug\FSharp.MongoDB.Driver.Tests.xml
26 |
27 |
28 | pdbonly
29 | true
30 | true
31 | bin\Release\
32 | TRACE
33 | 3
34 | bin\Release\FSharp.MongoDB.Driver.Tests.xml
35 |
36 |
37 |
38 | True
39 |
40 |
41 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Bson.dll
42 | True
43 |
44 |
45 | ..\..\lib\mongo-csharp-driver\MongoDB.Driver.Core\bin\Debug\MongoDB.Driver.Core.dll
46 |
47 |
48 |
49 | ..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll
50 | True
51 |
52 |
53 |
54 |
55 |
56 | ..\..\packages\Unquote.2.2.2\lib\net40\Unquote.dll
57 | True
58 |
59 |
60 |
61 |
62 | ExpressibleMongoTests.fs
63 |
64 |
65 | MongoBackboneTests.fs
66 |
67 |
68 | QuotableMongoTests.fs
69 |
70 |
71 | TypedQuotableMongoTests.fs
72 |
73 |
74 |
75 |
76 |
77 |
78 | FSharp.MongoDB.Driver
79 | {f2f775c4-7c17-4e02-a122-123514fc15c6}
80 | True
81 |
82 |
83 |
84 | 11
85 |
86 |
87 |
88 |
95 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.Tests/MongoBackboneTests.fs:
--------------------------------------------------------------------------------
1 | (* Copyright (c) 2013 MongoDB, Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | *)
15 |
16 | namespace FSharp.MongoDB.Driver.Tests
17 |
18 | open System.Net
19 |
20 | open MongoDB.Bson
21 |
22 | open MongoDB.Driver.Core
23 | open MongoDB.Driver.Core.Protocol
24 | open MongoDB.Driver.Core.Protocol.Messages
25 |
26 | open NUnit.Framework
27 | open Swensen.Unquote
28 |
29 | open FSharp.MongoDB.Driver
30 |
31 | module MongoBackbone =
32 |
33 | []
34 | module Configuration =
35 |
36 | let internal backbone = MongoBackbone(Backbone.DefaultSettings.all)
37 |
38 | let db = "fsharpdrivertests"
39 |
40 | []
41 | module Exceptions =
42 |
43 | let clctn = "failureops"
44 |
45 | []
46 | let ``drop collection``() =
47 | backbone.DropCollection db clctn|> ignore
48 |
49 | []
50 | let ``succeed when iterate through cursor twice``() =
51 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
52 | BsonElement("item", BsonString("pencil"));
53 | BsonElement("qty", BsonInt32(50));
54 | BsonElement("type", BsonString("no.2")) ]);
55 | BsonDocument([ BsonElement("item", BsonString("pen"));
56 | BsonElement("qty", BsonInt32(20)) ]);
57 | BsonDocument([ BsonElement("item", BsonString("eraser"));
58 | BsonElement("qty", BsonInt32(25)) ]) ]
59 |
60 | let insertFlags = InsertFlags.None
61 | let insertSettings = Operation.DefaultSettings.insert
62 |
63 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
64 |
65 | let query = BsonDocument()
66 | let project = BsonDocument()
67 |
68 | let queryFlags = QueryFlags.None
69 | let querySettings = Operation.DefaultSettings.query
70 |
71 | let res = backbone.Find db clctn query project 0 0 queryFlags querySettings
72 |
73 | for _ in [1 .. 2] do for _ in res do ()
74 |
75 | []
76 | [)>]
77 | let ``fail when insert duplicate keys``() =
78 | let id = 11 // make clear that all the documents use the same _id
79 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(id));
80 | BsonElement("item", BsonString("pencil"));
81 | BsonElement("qty", BsonInt32(50));
82 | BsonElement("type", BsonString("no.2")) ]);
83 | BsonDocument([ BsonElement("_id", BsonInt32(id));
84 | BsonElement("item", BsonString("pen"));
85 | BsonElement("qty", BsonInt32(20)) ]);
86 | BsonDocument([ BsonElement("_id", BsonInt32(id));
87 | BsonElement("item", BsonString("eraser"));
88 | BsonElement("qty", BsonInt32(25)) ]) ]
89 |
90 | let insertFlags = InsertFlags.None
91 | let insertSettings = { Operation.DefaultSettings.insert with WriteConcern = Some WriteConcern.Acknowledged }
92 |
93 | try
94 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
95 | with
96 | | :? System.AggregateException as exn ->
97 | for inner in exn.InnerExceptions do
98 | if inner.GetType() = typeof then raise inner
99 | reraise() // unexpected (inner) exception
100 |
101 | []
102 | [)>]
103 | let ``fail when invalid update command``() =
104 | let doc = BsonDocument([ BsonElement("item", BsonString("card"));
105 | BsonElement("qty", BsonInt32(15)) ])
106 |
107 | let insertFlags = InsertFlags.None
108 | let insertSettings = Operation.DefaultSettings.insert
109 |
110 | backbone.Insert db clctn doc insertFlags insertSettings |> ignore
111 |
112 | let updateQuery = BsonDocument()
113 | let update = BsonDocument("qty", BsonDocument("$inc", BsonInt32(-1))) // careful here
114 |
115 | let updateFlags = UpdateFlags.None
116 | let updateSettings = { Operation.DefaultSettings.update with CheckUpdateDocument = Some true }
117 |
118 | try
119 | backbone.Update db clctn updateQuery update updateFlags updateSettings |> ignore
120 | with
121 | | :? System.AggregateException as exn ->
122 | for inner in exn.InnerExceptions do
123 | if inner.GetType() = typeof then raise inner
124 | reraise() // unexpected (inner) exception
125 |
126 | []
127 | module InsertOps =
128 |
129 | let clctn = "insertops"
130 |
131 | []
132 | let ``drop collection``() =
133 | backbone.DropCollection db clctn |> ignore
134 |
135 | []
136 | let ``test insert without _id``() =
137 | let doc = BsonDocument([ BsonElement("item", BsonString("card"));
138 | BsonElement("qty", BsonInt32(15)) ])
139 |
140 | let insertFlags = InsertFlags.None
141 | let insertSettings = { Operation.DefaultSettings.insert with AssignIdOnInsert = Some false }
142 |
143 | backbone.Insert db clctn doc insertFlags insertSettings |> ignore
144 |
145 | let query = BsonDocument()
146 | let project = BsonDocument()
147 |
148 | let queryFlags = QueryFlags.None
149 | let querySettings = Operation.DefaultSettings.query
150 |
151 | let res = backbone.Find db clctn query project 0 0 queryFlags querySettings |> Seq.toList
152 |
153 | res.Length =? 1 // should only have single document in collection
154 | let found = res.Head
155 |
156 | // Check that an _id field was added to the document
157 | test <@ found.Contains "_id" = true @>
158 |
159 | // Check that found document contains correct values for elements of inserted document
160 | for elem in doc do
161 | test <@ elem.Value = found.[elem.Name] @>
162 |
163 | // Check that found document contains no other fields than previously examined
164 | test <@ doc.ElementCount + 1 = found.ElementCount @>
165 |
166 | []
167 | let ``test insert with _id``() =
168 | let doc = BsonDocument([ BsonElement("_id", BsonInt32(10));
169 | BsonElement("item", BsonString("box"));
170 | BsonElement("qty", BsonInt32(15)) ])
171 |
172 | let insertFlags = InsertFlags.None
173 | let insertSettings = Operation.DefaultSettings.insert
174 |
175 | backbone.Insert db clctn doc insertFlags insertSettings |> ignore
176 |
177 | let query = BsonDocument()
178 | let project = BsonDocument()
179 |
180 | let queryFlags = QueryFlags.None
181 | let querySettings = Operation.DefaultSettings.query
182 |
183 | let res = backbone.Find db clctn query project 0 0 queryFlags querySettings |> Seq.toList
184 |
185 | res.Length =? 1 // should only have single document in collection
186 | let found = res.Head
187 |
188 | // Check that found document contains correct values for elements of inserted document
189 | for elem in doc do
190 | test <@ elem.Value = found.[elem.Name] @>
191 |
192 | // Check that found document contains no other fields than previously examined
193 | test <@ doc.ElementCount = found.ElementCount @>
194 |
195 | []
196 | let ``test bulk insert``() =
197 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
198 | BsonElement("item", BsonString("pencil"));
199 | BsonElement("qty", BsonInt32(50));
200 | BsonElement("type", BsonString("no.2")) ]);
201 | BsonDocument([ BsonElement("item", BsonString("pen"));
202 | BsonElement("qty", BsonInt32(20)) ]);
203 | BsonDocument([ BsonElement("item", BsonString("eraser"));
204 | BsonElement("qty", BsonInt32(25)) ]) ]
205 |
206 | let insertFlags = InsertFlags.None
207 | let insertSettings = Operation.DefaultSettings.insert
208 |
209 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
210 |
211 | let query = BsonDocument()
212 | let project = BsonDocument()
213 |
214 | let queryFlags = QueryFlags.None
215 | let querySettings = Operation.DefaultSettings.query
216 |
217 | let res = backbone.Find db clctn query project 0 0 queryFlags querySettings |> Seq.toList
218 |
219 | res.Length =? docs.Length // should only have these document in collection
220 | for (doc, found) in List.zip docs res do
221 | // Check that found document contains correct values for elements of inserted document
222 | for elem in doc do
223 | test <@ elem.Value = found.[elem.Name] @>
224 |
225 | // Check that found document contains no other fields than previously examined
226 | test <@ doc.ElementCount = found.ElementCount @>
227 |
228 | []
229 | module UpdateOps =
230 |
231 | let clctn = "updateops"
232 |
233 | []
234 | let ``drop collection``() =
235 | backbone.DropCollection db clctn |> ignore
236 |
237 | []
238 | let ``test update single``() =
239 | let doc = BsonDocument([ BsonElement("item", BsonString("card"));
240 | BsonElement("qty", BsonInt32(15)) ])
241 |
242 | let insertFlags = InsertFlags.None
243 | let insertSettings = { Operation.DefaultSettings.insert with AssignIdOnInsert = Some false }
244 |
245 | backbone.Insert db clctn doc insertFlags insertSettings |> ignore
246 |
247 | let updateQuery = BsonDocument()
248 | let update = BsonDocument("$inc", BsonDocument("qty", BsonInt32(-1)))
249 |
250 | let updateFlags = UpdateFlags.None
251 | let updateSettings = Operation.DefaultSettings.update
252 |
253 | backbone.Update db clctn updateQuery update updateFlags updateSettings |> ignore
254 |
255 | let findQuery = BsonDocument()
256 | let project = BsonDocument()
257 |
258 | let queryFlags = QueryFlags.None
259 | let querySettings = Operation.DefaultSettings.query
260 |
261 | let res = backbone.Find db clctn findQuery project 0 0 queryFlags querySettings |> Seq.toList
262 |
263 | res.Length =? 1 // should only have single document in collection
264 | let found = res.Head
265 |
266 | // Check that found document contains correct values for elements of updated document
267 | for elem in doc do
268 | if elem.Name = "qty" then
269 | test <@ elem.Value.AsInt32 - 1 = found.[elem.Name].AsInt32 @>
270 | else
271 | test <@ elem.Value = found.[elem.Name] @>
272 |
273 | []
274 | let ``test update multi``() =
275 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
276 | BsonElement("item", BsonString("pencil"));
277 | BsonElement("qty", BsonInt32(50));
278 | BsonElement("type", BsonString("no.2")) ]);
279 | BsonDocument([ BsonElement("item", BsonString("pen"));
280 | BsonElement("qty", BsonInt32(20)) ]);
281 | BsonDocument([ BsonElement("item", BsonString("eraser"));
282 | BsonElement("qty", BsonInt32(25)) ]) ]
283 |
284 | let insertFlags = InsertFlags.None
285 | let insertSettings = Operation.DefaultSettings.insert
286 |
287 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
288 |
289 | let updateQuery = BsonDocument()
290 | let update = BsonDocument("$inc", BsonDocument("qty", BsonInt32(-1)))
291 |
292 | let updateFlags = UpdateFlags.Multi
293 | let updateSettings = Operation.DefaultSettings.update
294 |
295 | backbone.Update db clctn updateQuery update updateFlags updateSettings |> ignore
296 |
297 | let findQuery = BsonDocument()
298 | let project = BsonDocument()
299 |
300 | let queryFlags = QueryFlags.None
301 | let querySettings = Operation.DefaultSettings.query
302 |
303 | let res = backbone.Find db clctn findQuery project 0 0 queryFlags querySettings |> Seq.toList
304 |
305 | res.Length =? docs.Length // should only have these document in collection
306 | for (doc, found) in List.zip docs res do
307 | // Check that found document contains correct values for elements of inserted document
308 | for elem in doc do
309 | if elem.Name = "qty" then
310 | test <@ elem.Value.AsInt32 - 1 = found.[elem.Name].AsInt32 @>
311 | else
312 | test <@ elem.Value = found.[elem.Name] @>
313 |
314 | []
315 | let ``test upsert``() =
316 | let updateQuery = BsonDocument([ BsonElement("item", BsonString("card"));
317 | BsonElement("qty", BsonInt32(15)) ])
318 | let update = BsonDocument("$inc", BsonDocument("qty", BsonInt32(-1)))
319 |
320 | let updateFlags = UpdateFlags.Upsert
321 | let updateSettings = Operation.DefaultSettings.update
322 |
323 | backbone.Update db clctn updateQuery update updateFlags updateSettings |> ignore
324 |
325 | let findQuery = BsonDocument()
326 | let project = BsonDocument()
327 |
328 | let queryFlags = QueryFlags.None
329 | let querySettings = Operation.DefaultSettings.query
330 |
331 | let res = backbone.Find db clctn findQuery project 0 0 queryFlags querySettings |> Seq.toList
332 |
333 | res.Length =? 1 // should only have single document in collection
334 | let found = res.Head
335 |
336 | // Check that found document contains correct values for elements of updated document
337 | for elem in updateQuery do
338 | if elem.Name = "qty" then
339 | test <@ elem.Value.AsInt32 - 1 = found.[elem.Name].AsInt32 @>
340 | else
341 | test <@ elem.Value = found.[elem.Name] @>
342 |
343 | []
344 | module RemoveOps =
345 |
346 | let clctn = "removeops"
347 |
348 | []
349 | let ``drop collection``() =
350 | backbone.DropCollection db clctn |> ignore
351 |
352 | []
353 | let ``test remove single``() =
354 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
355 | BsonElement("item", BsonString("pencil"));
356 | BsonElement("qty", BsonInt32(50));
357 | BsonElement("type", BsonString("no.2")) ]);
358 | BsonDocument([ BsonElement("item", BsonString("pen"));
359 | BsonElement("qty", BsonInt32(20)) ]);
360 | BsonDocument([ BsonElement("item", BsonString("eraser"));
361 | BsonElement("qty", BsonInt32(25)) ]) ]
362 |
363 | let insertFlags = InsertFlags.None
364 | let insertSettings = { Operation.DefaultSettings.insert with AssignIdOnInsert = Some true }
365 |
366 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
367 |
368 | let removeQuery = BsonDocument("_id", BsonInt32(11))
369 |
370 | let deleteFlags = DeleteFlags.Single
371 | let removeSettings = Operation.DefaultSettings.remove
372 |
373 | backbone.Remove db clctn removeQuery deleteFlags removeSettings |> ignore
374 |
375 | let findQuery = BsonDocument()
376 | let project = BsonDocument()
377 |
378 | let queryFlags = QueryFlags.None
379 | let querySettings = Operation.DefaultSettings.query
380 |
381 | let res = backbone.Find db clctn findQuery project 0 0 queryFlags querySettings |> Seq.toList
382 |
383 | res.Length =? docs.Length - 1 // should have removed a single document from the collection
384 | for (doc, found) in List.zip (docs |> List.tail) res do
385 | // Check that found document contains correct values for elements of non-removed document
386 | for elem in doc do
387 | test <@ elem.Value = found.[elem.Name] @>
388 |
389 | // Check that found document contains no other fields than previously examined
390 | test <@ doc.ElementCount = found.ElementCount @>
391 |
392 | []
393 | let ``test remove multi``() =
394 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
395 | BsonElement("item", BsonString("pencil"));
396 | BsonElement("qty", BsonInt32(50));
397 | BsonElement("type", BsonString("no.2")) ]);
398 | BsonDocument([ BsonElement("item", BsonString("pen"));
399 | BsonElement("qty", BsonInt32(20)) ]);
400 | BsonDocument([ BsonElement("item", BsonString("eraser"));
401 | BsonElement("qty", BsonInt32(25)) ]) ]
402 |
403 | let insertFlags = InsertFlags.None
404 | let insertSettings = { Operation.DefaultSettings.insert with AssignIdOnInsert = Some true }
405 |
406 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
407 |
408 | let removeQuery = BsonDocument("qty", BsonDocument("$lte", BsonInt32(25)))
409 |
410 | let deleteFlags = DeleteFlags.None
411 | let removeSettings = Operation.DefaultSettings.remove
412 |
413 | backbone.Remove db clctn removeQuery deleteFlags removeSettings |> ignore
414 |
415 | let findQuery = BsonDocument()
416 | let project = BsonDocument()
417 |
418 | let queryFlags = QueryFlags.None
419 | let querySettings = Operation.DefaultSettings.query
420 |
421 | let res = backbone.Find db clctn findQuery project 0 0 queryFlags querySettings |> Seq.toList
422 |
423 | res.Length =? 1 // should have removed multiple documents from the collection
424 | let found = res |> List.head
425 |
426 | let doc = docs |> List.head
427 |
428 | // Check that found document contains correct values for elements of non-removed document
429 | for elem in doc do
430 | test <@ elem.Value = found.[elem.Name] @>
431 |
432 | // Check that found document contains no other fields than previously examined
433 | test <@ doc.ElementCount = found.ElementCount @>
434 |
435 | []
436 | let ``test remove all``() =
437 | let docs = [ BsonDocument([ BsonElement("_id", BsonInt32(11));
438 | BsonElement("item", BsonString("pencil"));
439 | BsonElement("qty", BsonInt32(50));
440 | BsonElement("type", BsonString("no.2")) ]);
441 | BsonDocument([ BsonElement("item", BsonString("pen"));
442 | BsonElement("qty", BsonInt32(20)) ]);
443 | BsonDocument([ BsonElement("item", BsonString("eraser"));
444 | BsonElement("qty", BsonInt32(25)) ]) ]
445 |
446 | let insertFlags = InsertFlags.None
447 | let insertSettings = { Operation.DefaultSettings.insert with AssignIdOnInsert = Some true }
448 |
449 | backbone.BulkInsert db clctn docs insertFlags insertSettings |> ignore
450 |
451 | let removeQuery = BsonDocument()
452 |
453 | let deleteFlags = DeleteFlags.None
454 | let removeSettings = Operation.DefaultSettings.remove
455 |
456 | backbone.Remove db clctn removeQuery deleteFlags removeSettings |> ignore
457 |
458 | let findQuery = BsonDocument()
459 | let project = BsonDocument()
460 |
461 | let queryFlags = QueryFlags.None
462 | let querySettings = Operation.DefaultSettings.query
463 |
464 | let res = backbone.Find db clctn findQuery project 0 0 queryFlags querySettings |> Seq.toList
465 |
466 | res.Length =? 0 // should have removed all documents from the collection
467 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/FSharp.MongoDB.Driver.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------