├── .config
└── dotnet-tools.json
├── .editorconfig
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── config.yml
│ ├── feature_request.md
│ └── question.md
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ ├── build.yml
│ ├── codeql.yml
│ └── deps-review.yml
├── .gitignore
├── .idea
└── .idea.JsonApiDotNetCore.MongoDb
│ └── .idea
│ ├── .gitignore
│ └── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── Build.ps1
├── CSharpGuidelinesAnalyzer.config
├── CodingGuidelines.ruleset
├── Directory.Build.props
├── JetBrainsInspectCodeTransform.xslt
├── JsonApiDotNetCore.MongoDb.sln
├── JsonApiDotNetCore.MongoDb.sln.DotSettings
├── LICENSE
├── PackageReadme.md
├── README.md
├── WarningSeverities.DotSettings
├── appveyor.yml
├── cleanupcode.ps1
├── codecov.yml
├── inspectcode.ps1
├── package-icon.png
├── package-versions.props
├── run-docker-mongodb.ps1
├── src
├── Examples
│ ├── GettingStarted
│ │ ├── GettingStarted.csproj
│ │ ├── Models
│ │ │ └── Book.cs
│ │ ├── Program.cs
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── README.md
│ │ └── appsettings.json
│ └── JsonApiDotNetCoreMongoDbExample
│ │ ├── Controllers
│ │ └── OperationsController.cs
│ │ ├── Definitions
│ │ └── TodoItemDefinition.cs
│ │ ├── JsonApiDotNetCoreMongoDbExample.csproj
│ │ ├── Models
│ │ ├── TodoItem.cs
│ │ └── TodoItemPriority.cs
│ │ ├── Program.cs
│ │ ├── Properties
│ │ └── launchSettings.json
│ │ └── appsettings.json
└── JsonApiDotNetCore.MongoDb
│ ├── AtomicOperations
│ ├── MongoTransaction.cs
│ └── MongoTransactionFactory.cs
│ ├── Configuration
│ ├── ResourceGraphExtensions.cs
│ └── ServiceCollectionExtensions.cs
│ ├── Errors
│ ├── AttributeComparisonInFilterNotSupportedException.cs
│ └── UnsupportedRelationshipException.cs
│ ├── JsonApiDotNetCore.MongoDb.csproj
│ ├── PolyfillCollectionExtensions.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Queries
│ └── HideRelationshipsSparseFieldSetCache.cs
│ ├── ReadOnlySet.cs
│ ├── Repositories
│ ├── IMongoDataAccess.cs
│ ├── MongoDataAccess.cs
│ ├── MongoQueryExpressionValidator.cs
│ └── MongoRepository.cs
│ └── Resources
│ ├── FreeStringMongoIdentifiable.cs
│ ├── HexStringMongoIdentifiable.cs
│ └── IMongoIdentifiable.cs
├── test
├── JsonApiDotNetCoreMongoDbTests
│ ├── IntegrationTests
│ │ ├── AtomicOperations
│ │ │ ├── AtomicOperationsCollectionFixture.cs
│ │ │ ├── AtomicOperationsFixture.cs
│ │ │ ├── BaseForAtomicOperationsTestsThatChangeOptions.cs
│ │ │ ├── Creating
│ │ │ │ ├── AtomicCreateResourceTests.cs
│ │ │ │ ├── AtomicCreateResourceWithClientGeneratedIdTests.cs
│ │ │ │ ├── AtomicCreateResourceWithToManyRelationshipTests.cs
│ │ │ │ └── AtomicCreateResourceWithToOneRelationshipTests.cs
│ │ │ ├── Deleting
│ │ │ │ └── AtomicDeleteResourceTests.cs
│ │ │ ├── ImplicitlyChangingTextLanguageDefinition.cs
│ │ │ ├── LocalIds
│ │ │ │ └── AtomicLocalIdTests.cs
│ │ │ ├── Lyric.cs
│ │ │ ├── Meta
│ │ │ │ ├── AtomicResourceMetaTests.cs
│ │ │ │ ├── MusicTrackMetaDefinition.cs
│ │ │ │ └── TextLanguageMetaDefinition.cs
│ │ │ ├── Mixed
│ │ │ │ └── MaximumOperationsPerRequestTests.cs
│ │ │ ├── MusicTrack.cs
│ │ │ ├── OperationsController.cs
│ │ │ ├── OperationsDbContext.cs
│ │ │ ├── OperationsFakers.cs
│ │ │ ├── Performer.cs
│ │ │ ├── Playlist.cs
│ │ │ ├── RecordCompany.cs
│ │ │ ├── TextLanguage.cs
│ │ │ ├── Transactions
│ │ │ │ ├── AtomicRollbackTests.cs
│ │ │ │ ├── AtomicTransactionConsistencyTests.cs
│ │ │ │ ├── LyricRepository.cs
│ │ │ │ ├── MusicTrackRepository.cs
│ │ │ │ └── PerformerRepository.cs
│ │ │ └── Updating
│ │ │ │ ├── Relationships
│ │ │ │ ├── AtomicAddToToManyRelationshipTests.cs
│ │ │ │ ├── AtomicRemoveFromToManyRelationshipTests.cs
│ │ │ │ ├── AtomicReplaceToManyRelationshipTests.cs
│ │ │ │ └── AtomicUpdateToOneRelationshipTests.cs
│ │ │ │ └── Resources
│ │ │ │ ├── AtomicReplaceToManyRelationshipTests.cs
│ │ │ │ ├── AtomicUpdateResourceTests.cs
│ │ │ │ └── AtomicUpdateToOneRelationshipTests.cs
│ │ ├── HitCountingResourceDefinition.cs
│ │ ├── Meta
│ │ │ ├── MetaDbContext.cs
│ │ │ ├── MetaFakers.cs
│ │ │ ├── ResourceMetaTests.cs
│ │ │ ├── SupportTicket.cs
│ │ │ ├── SupportTicketDefinition.cs
│ │ │ └── TopLevelCountTests.cs
│ │ ├── QueryStrings
│ │ │ ├── AccountPreferences.cs
│ │ │ ├── Blog.cs
│ │ │ ├── BlogPost.cs
│ │ │ ├── Comment.cs
│ │ │ ├── Filtering
│ │ │ │ ├── FilterDataTypeTests.cs
│ │ │ │ ├── FilterDbContext.cs
│ │ │ │ ├── FilterDepthTests.cs
│ │ │ │ ├── FilterOperatorTests.cs
│ │ │ │ ├── FilterTests.cs
│ │ │ │ └── FilterableResource.cs
│ │ │ ├── Includes
│ │ │ │ └── IncludeTests.cs
│ │ │ ├── Label.cs
│ │ │ ├── LabelColor.cs
│ │ │ ├── LoginAttempt.cs
│ │ │ ├── Pagination
│ │ │ │ ├── PaginationWithTotalCountTests.cs
│ │ │ │ └── RangeValidationTests.cs
│ │ │ ├── QueryStringDbContext.cs
│ │ │ ├── QueryStringFakers.cs
│ │ │ ├── Sorting
│ │ │ │ └── SortTests.cs
│ │ │ ├── SparseFieldSets
│ │ │ │ ├── ResourceCaptureStore.cs
│ │ │ │ ├── ResultCapturingRepository.cs
│ │ │ │ └── SparseFieldSetTests.cs
│ │ │ └── WebAccount.cs
│ │ ├── ReadWrite
│ │ │ ├── Creating
│ │ │ │ ├── CreateResourceTests.cs
│ │ │ │ ├── CreateResourceWithClientGeneratedIdTests.cs
│ │ │ │ ├── CreateResourceWithToManyRelationshipTests.cs
│ │ │ │ └── CreateResourceWithToOneRelationshipTests.cs
│ │ │ ├── Deleting
│ │ │ │ └── DeleteResourceTests.cs
│ │ │ ├── Fetching
│ │ │ │ ├── FetchRelationshipTests.cs
│ │ │ │ └── FetchResourceTests.cs
│ │ │ ├── ImplicitlyChangingWorkItemDefinition.cs
│ │ │ ├── ImplicitlyChangingWorkItemGroupDefinition.cs
│ │ │ ├── ModelWithIntId.cs
│ │ │ ├── ReadWriteDbContext.cs
│ │ │ ├── ReadWriteFakers.cs
│ │ │ ├── RgbColor.cs
│ │ │ ├── Updating
│ │ │ │ ├── Relationships
│ │ │ │ │ ├── AddToToManyRelationshipTests.cs
│ │ │ │ │ ├── RemoveFromToManyRelationshipTests.cs
│ │ │ │ │ ├── ReplaceToManyRelationshipTests.cs
│ │ │ │ │ └── UpdateToOneRelationshipTests.cs
│ │ │ │ └── Resources
│ │ │ │ │ ├── ReplaceToManyRelationshipTests.cs
│ │ │ │ │ ├── UpdateResourceTests.cs
│ │ │ │ │ └── UpdateToOneRelationshipTests.cs
│ │ │ ├── UserAccount.cs
│ │ │ ├── WorkItem.cs
│ │ │ ├── WorkItemGroup.cs
│ │ │ ├── WorkItemPriority.cs
│ │ │ └── WorkTag.cs
│ │ ├── ResourceDefinitionExtensibilityPoints.cs
│ │ ├── ResourceDefinitionHitCounter.cs
│ │ ├── ResourceDefinitions
│ │ │ └── Reading
│ │ │ │ ├── IClientSettingsProvider.cs
│ │ │ │ ├── Moon.cs
│ │ │ │ ├── MoonDefinition.cs
│ │ │ │ ├── Planet.cs
│ │ │ │ ├── PlanetDefinition.cs
│ │ │ │ ├── ResourceDefinitionReadTests.cs
│ │ │ │ ├── Star.cs
│ │ │ │ ├── StarDefinition.cs
│ │ │ │ ├── StarKind.cs
│ │ │ │ ├── TestClientSettingsProvider.cs
│ │ │ │ ├── UniverseDbContext.cs
│ │ │ │ └── UniverseFakers.cs
│ │ └── TestableStartup.cs
│ └── JsonApiDotNetCoreMongoDbTests.csproj
└── TestBuildingBlocks
│ ├── DateTimeExtensions.cs
│ ├── DummyTest.cs
│ ├── FakerExtensions.cs
│ ├── FluentExtensions.cs
│ ├── FluentMetaExtensions.cs
│ ├── HttpResponseMessageExtensions.cs
│ ├── IntegrationTest.cs
│ ├── IntegrationTestContext.cs
│ ├── MarkedText.cs
│ ├── MongoDbContextShim.cs
│ ├── MongoDbSetShim.cs
│ ├── MongoRunnerProvider.cs
│ ├── NeverSameResourceChangeTracker.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── ResourceTypeFinder.cs
│ ├── ServiceCollectionExtensions.cs
│ ├── TestBuildingBlocks.csproj
│ ├── TestControllerProvider.cs
│ ├── Unknown.cs
│ └── appsettings.json
└── tests.runsettings
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "jetbrains.resharper.globaltools": {
6 | "version": "2024.3.6",
7 | "commands": [
8 | "jb"
9 | ],
10 | "rollForward": false
11 | },
12 | "regitlint": {
13 | "version": "6.3.13",
14 | "commands": [
15 | "regitlint"
16 | ],
17 | "rollForward": false
18 | },
19 | "dotnet-reportgenerator-globaltool": {
20 | "version": "5.4.5",
21 | "commands": [
22 | "reportgenerator"
23 | ],
24 | "rollForward": false
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: json-api-dotnet
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve.
4 | title: ''
5 | labels: 'bug'
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | #### DESCRIPTION
13 |
14 |
15 | #### STEPS TO REPRODUCE
16 |
17 |
18 | 1.
19 | 2.
20 | 3.
21 |
22 | #### EXPECTED BEHAVIOR
23 |
24 |
25 | #### ACTUAL BEHAVIOR
26 |
27 |
28 | #### VERSIONS USED
29 | - JsonApiDotNetCore.MongoDb version:
30 | - JsonApiDotNetCore version:
31 | - ASP.NET Core version:
32 | - MongoDB version:
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: Documentation
4 | url: https://www.jsonapi.net/usage/resources/index.html
5 | about: Read our comprehensive documentation.
6 | - name: Sponsor JsonApiDotNetCore
7 | url: https://github.com/sponsors/json-api-dotnet
8 | about: Help the continued development.
9 | - name: Ask on Gitter
10 | url: https://gitter.im/json-api-dotnet-core/Lobby
11 | about: Get in touch with the whole community.
12 | - name: Ask on Stack Overflow
13 | url: https://stackoverflow.com/questions/tagged/json-api
14 | about: The best place for asking general-purpose questions.
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project.
4 | title: ''
5 | labels: 'enhancement'
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | **Is your feature request related to a problem? Please describe.**
13 |
14 |
15 | **Describe the solution you'd like**
16 |
17 |
18 | **Describe alternatives you've considered**
19 |
20 |
21 | **Additional context**
22 |
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Ask a question.
4 | title: ''
5 | labels: 'question'
6 | assignees: ''
7 |
8 | ---
9 |
10 |
13 |
14 | #### SUMMARY
15 |
18 |
19 | #### DETAILS
20 |
24 |
25 |
26 | #### STEPS TO REPRODUCE
27 |
30 |
31 | 1.
32 | 2.
33 | 3.
34 |
35 | #### VERSIONS USED
36 | - JsonApiDotNetCore.MongoDb version:
37 | - JsonApiDotNetCore version:
38 | - ASP.NET Core version:
39 | - MongoDB version:
40 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Closes #{ISSUE_NUMBER}
4 |
5 | #### QUALITY CHECKLIST
6 | - [ ] Changes implemented in code
7 | - [ ] Complies with our [contributing guidelines](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/.github/CONTRIBUTING.md)
8 | - [ ] Adapted tests
9 | - [ ] Documentation updated
10 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | pull-request-branch-name:
8 | separator: "-"
9 | - package-ecosystem: nuget
10 | directory: "/"
11 | schedule:
12 | interval: daily
13 | pull-request-branch-name:
14 | separator: "-"
15 | open-pull-requests-limit: 25
16 | ignore:
17 | # Block updates to all exposed dependencies of the NuGet packages we produce, as updating them would be a breaking change.
18 | - dependency-name: "JsonApiDotNetCore*"
19 | - dependency-name: "MongoDB.Driver*"
20 | # Block major updates of packages that require a matching .NET version.
21 | - dependency-name: "Microsoft.AspNetCore*"
22 | update-types: ["version-update:semver-major"]
23 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ 'master', 'release/**' ]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [ 'master', 'release/**' ]
9 | schedule:
10 | - cron: '0 0 * * 5'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: 'ubuntu-latest'
16 | timeout-minutes: 60
17 | permissions:
18 | actions: read
19 | contents: read
20 | security-events: write
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | language: [ 'csharp' ]
25 | steps:
26 | - name: Setup .NET
27 | uses: actions/setup-dotnet@v4
28 | with:
29 | dotnet-version: |
30 | 8.0.*
31 | 9.0.*
32 | - name: Git checkout
33 | uses: actions/checkout@v4
34 | - name: Initialize CodeQL
35 | uses: github/codeql-action/init@v3
36 | with:
37 | languages: ${{ matrix.language }}
38 | - name: Autobuild
39 | uses: github/codeql-action/autobuild@v3
40 | - name: Perform CodeQL Analysis
41 | uses: github/codeql-action/analyze@v3
42 | with:
43 | category: "/language:${{matrix.language}}"
44 |
--------------------------------------------------------------------------------
/.github/workflows/deps-review.yml:
--------------------------------------------------------------------------------
1 | name: 'Dependency Review'
2 | on: [pull_request]
3 |
4 | permissions:
5 | contents: read
6 |
7 | jobs:
8 | dependency-review:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: 'Checkout Repository'
12 | uses: actions/checkout@v4
13 | - name: 'Dependency Review'
14 | uses: actions/dependency-review-action@v4
15 |
--------------------------------------------------------------------------------
/.idea/.idea.JsonApiDotNetCore.MongoDb/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Empty .gitignore file to prevent Rider from adding one
2 |
--------------------------------------------------------------------------------
/.idea/.idea.JsonApiDotNetCore.MongoDb/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/.idea.JsonApiDotNetCore.MongoDb/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Build.ps1:
--------------------------------------------------------------------------------
1 | function VerifySuccessExitCode {
2 | if ($LastExitCode -ne 0) {
3 | throw "Command failed with exit code $LastExitCode."
4 | }
5 | }
6 |
7 | Write-Host "$(pwsh --version)"
8 | Write-Host "Active .NET SDK: $(dotnet --version)"
9 | Write-Host "Using version suffix: $versionSuffix"
10 |
11 | Remove-Item -Recurse -Force artifacts -ErrorAction SilentlyContinue
12 | Remove-Item -Recurse -Force * -Include coverage.cobertura.xml
13 |
14 | dotnet tool restore
15 | VerifySuccessExitCode
16 |
17 | dotnet build --configuration Release
18 | VerifySuccessExitCode
19 |
20 | dotnet test --no-build --configuration Release --verbosity quiet --collect:"XPlat Code Coverage"
21 | VerifySuccessExitCode
22 |
23 | dotnet reportgenerator -reports:**\coverage.cobertura.xml -targetdir:artifacts\coverage -filefilters:-*.g.cs
24 | VerifySuccessExitCode
25 |
26 | dotnet pack --no-build --configuration Release --output artifacts/packages
27 | VerifySuccessExitCode
28 |
--------------------------------------------------------------------------------
/CSharpGuidelinesAnalyzer.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CodingGuidelines.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | enable
4 | latest
5 | enable
6 | false
7 | false
8 | true
9 | Recommended
10 | $(MSBuildThisFileDirectory)CodingGuidelines.ruleset
11 | $(MSBuildThisFileDirectory)tests.runsettings
12 | 5.7.2
13 | pre
14 | direct
15 |
16 |
17 |
18 |
25 | IDE0028;IDE0300;IDE0301;IDE0302;IDE0303;IDE0304;IDE0305;IDE0306
26 | $(NoWarn);$(UseCollectionExpressionRules)
27 |
28 |
29 |
30 | $(NoWarn);AV2210
31 |
32 |
33 |
34 | $(NoWarn);1591
35 | true
36 | true
37 |
38 |
39 |
40 | true
41 |
42 |
43 |
44 | $(NoWarn);CA1707;CA1062
45 |
46 |
47 |
48 | $(NoWarn);CA1062
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/JetBrainsInspectCodeTransform.xslt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | JetBrains Inspect Code Report
10 |
11 |
16 |
17 |
18 | JetBrains InspectCode Report
19 |
20 |
21 |
22 | :
23 |
24 |
25 |
26 | File |
27 | Line Number |
28 | Type |
29 | Message |
30 |
31 |
32 |
33 |
34 |
35 | |
36 |
37 |
38 | |
39 |
40 |
41 | |
42 |
43 |
44 | |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020 Alvaro Nicoli
2 | Copyright (c) 2021 Bart Koelman
3 |
4 | MIT License
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining
7 | a copy of this software and associated documentation files (the
8 | "Software"), to deal in the Software without restriction, including
9 | without limitation the rights to use, copy, modify, merge, publish,
10 | distribute, sublicense, and/or sell copies of the Software, and to
11 | permit persons to whom the Software is furnished to do so, subject to
12 | the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/PackageReadme.md:
--------------------------------------------------------------------------------
1 | [MongoDB](https://www.mongodb.com/) persistence for [JsonApiDotNetCore](https://www.jsonapi.net/), which is a framework for building JSON:API compliant REST APIs using ASP.NET Core.
2 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Visual Studio 2022
2 |
3 | version: '{build}'
4 |
5 | branches:
6 | only:
7 | - master
8 | - /release\/.+/
9 |
10 | build: off
11 | test: off
12 | deploy: off
13 |
--------------------------------------------------------------------------------
/cleanupcode.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 7.0
2 |
3 | # This script reformats (part of) the codebase to make it compliant with our coding guidelines.
4 |
5 | param(
6 | # Git branch name or base commit hash to reformat only the subset of changed files. Omit for all files.
7 | [string] $revision
8 | )
9 |
10 | function VerifySuccessExitCode {
11 | if ($LastExitCode -ne 0) {
12 | throw "Command failed with exit code $LastExitCode."
13 | }
14 | }
15 |
16 | dotnet tool restore
17 | VerifySuccessExitCode
18 |
19 | dotnet restore
20 | VerifySuccessExitCode
21 |
22 | if ($revision) {
23 | $headCommitHash = git rev-parse HEAD
24 | VerifySuccessExitCode
25 |
26 | $baseCommitHash = git rev-parse $revision
27 | VerifySuccessExitCode
28 |
29 | if ($baseCommitHash -eq $headCommitHash) {
30 | Write-Output "Running code cleanup on staged/unstaged files."
31 | dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --properties:RunAnalyzers=false --jb --verbosity=WARN -f staged,modified
32 | VerifySuccessExitCode
33 | }
34 | else {
35 | Write-Output "Running code cleanup on commit range $baseCommitHash..$headCommitHash, including staged/unstaged files."
36 | dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --max-runs=5 --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --properties:RunAnalyzers=false --jb --verbosity=WARN -f staged,modified,commits -a $headCommitHash -b $baseCommitHash
37 | VerifySuccessExitCode
38 | }
39 | }
40 | else {
41 | Write-Output "Running code cleanup on all files."
42 | dotnet regitlint -s JsonApiDotNetCore.MongoDb.sln --print-command --skip-tool-check --jb --dotnetcoresdk=$(dotnet --version) --jb-profile="JADNC Full Cleanup" --jb --properties:Configuration=Release --jb --properties:RunAnalyzers=false --jb --verbosity=WARN
43 | VerifySuccessExitCode
44 | }
45 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | target: auto
6 | threshold: 10%
7 | informational: true
8 | patch:
9 | default:
10 | informational: true
11 |
12 | github_checks:
13 | annotations: false
14 |
--------------------------------------------------------------------------------
/inspectcode.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 7.0
2 |
3 | # This script runs code inspection and opens the results in a web browser.
4 |
5 | dotnet tool restore
6 |
7 | if ($LastExitCode -ne 0) {
8 | throw "Tool restore failed with exit code $LastExitCode"
9 | }
10 |
11 | $outputPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'jetbrains-inspectcode-results.xml')
12 | $resultPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'jetbrains-inspectcode-results.html')
13 | dotnet jb inspectcode JsonApiDotNetCore.MongoDb.sln --dotnetcoresdk=$(dotnet --version) --build --output="$outputPath" --format="xml" --profile=WarningSeverities.DotSettings --properties:Configuration=Release --properties:RunAnalyzers=false --severity=WARNING --verbosity=WARN -dsl=GlobalAll -dsl=GlobalPerProduct -dsl=SolutionPersonal -dsl=ProjectPersonal
14 |
15 | if ($LastExitCode -ne 0) {
16 | throw "Code inspection failed with exit code $LastExitCode"
17 | }
18 |
19 | [xml]$xml = Get-Content "$outputPath"
20 | if ($xml.report.Issues -and $xml.report.Issues.Project) {
21 | $xslt = new-object System.Xml.Xsl.XslCompiledTransform;
22 | $xslt.Load("$pwd/JetBrainsInspectCodeTransform.xslt");
23 | $xslt.Transform($outputPath, $resultPath);
24 |
25 | Write-Output "Opening results in browser"
26 | Invoke-Item "$resultPath"
27 | }
28 |
--------------------------------------------------------------------------------
/package-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/48e257c4b915304512ec6c692107329e4ca4d3a2/package-icon.png
--------------------------------------------------------------------------------
/package-versions.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 5.7.1
5 | 3.3.0
6 |
7 |
8 | 35.6.*
9 | 6.0.*
10 | 3.1.*
11 | 7.2.*
12 | 2.4.*
13 | 2.0.*
14 | 3.3.*
15 | 17.13.*
16 | 2.9.*
17 | 2.8.*
18 |
19 |
20 |
21 |
22 | 9.0.*
23 |
24 |
25 |
26 |
27 | 8.0.*
28 |
29 |
30 |
--------------------------------------------------------------------------------
/run-docker-mongodb.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 7.0
2 |
3 | # This script starts a MongoDB database in a docker container, which is required for running examples locally.
4 |
5 | docker container stop jsonapi-mongo-db
6 | docker run --pull always --rm --detach --name jsonapi-mongo-db -p 27017:27017 mongo:latest
7 |
--------------------------------------------------------------------------------
/src/Examples/GettingStarted/GettingStarted.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net9.0;net8.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Examples/GettingStarted/Models/Book.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 | using JsonApiDotNetCore.MongoDb.Resources;
3 | using JsonApiDotNetCore.Resources.Annotations;
4 |
5 | namespace GettingStarted.Models;
6 |
7 | [UsedImplicitly(ImplicitUseTargetFlags.Members)]
8 | [Resource]
9 | public sealed class Book : HexStringMongoIdentifiable
10 | {
11 | [Attr]
12 | public string Title { get; set; } = null!;
13 |
14 | [Attr]
15 | public string Author { get; set; } = null!;
16 |
17 | [Attr]
18 | public int PublishYear { get; set; }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Examples/GettingStarted/Program.cs:
--------------------------------------------------------------------------------
1 | using GettingStarted.Models;
2 | using JsonApiDotNetCore.Configuration;
3 | using JsonApiDotNetCore.MongoDb.Configuration;
4 | using JsonApiDotNetCore.MongoDb.Repositories;
5 | using Microsoft.Extensions.DependencyInjection.Extensions;
6 | using MongoDB.Driver;
7 |
8 | WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
9 |
10 | // Add services to the container.
11 |
12 | builder.Services.TryAddSingleton(_ =>
13 | {
14 | var client = new MongoClient(builder.Configuration.GetSection("DatabaseSettings:ConnectionString").Value);
15 | return client.GetDatabase(builder.Configuration.GetSection("DatabaseSettings:Database").Value);
16 | });
17 |
18 | builder.Services.AddJsonApi(options =>
19 | {
20 | options.Namespace = "api";
21 | options.UseRelativeLinks = true;
22 | options.IncludeTotalResourceCount = true;
23 |
24 | #if DEBUG
25 | options.IncludeExceptionStackTraceInErrors = true;
26 | options.IncludeRequestBodyInErrors = true;
27 | options.SerializerOptions.WriteIndented = true;
28 | #endif
29 | }, resources: resourceGraphBuilder => resourceGraphBuilder.Add());
30 |
31 | builder.Services.AddJsonApiMongoDb();
32 |
33 | builder.Services.AddResourceRepository>();
34 |
35 | WebApplication app = builder.Build();
36 |
37 | // Configure the HTTP request pipeline.
38 |
39 | app.UseRouting();
40 | app.UseJsonApi();
41 | app.MapControllers();
42 |
43 | var database = app.Services.GetRequiredService();
44 | await CreateSampleDataAsync(database);
45 |
46 | await app.RunAsync();
47 |
48 | static async Task CreateSampleDataAsync(IMongoDatabase database)
49 | {
50 | await database.DropCollectionAsync(nameof(Book));
51 |
52 | await database.GetCollection(nameof(Book)).InsertManyAsync(new[]
53 | {
54 | new Book
55 | {
56 | Title = "Frankenstein",
57 | PublishYear = 1818,
58 | Author = "Mary Shelley"
59 | },
60 | new Book
61 | {
62 | Title = "Robinson Crusoe",
63 | PublishYear = 1719,
64 | Author = "Daniel Defoe"
65 | },
66 | new Book
67 | {
68 | Title = "Gulliver's Travels",
69 | PublishYear = 1726,
70 | Author = "Jonathan Swift"
71 | }
72 | });
73 | }
74 |
--------------------------------------------------------------------------------
/src/Examples/GettingStarted/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:24141"
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "launchUrl": "api/books",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "Kestrel": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "launchUrl": "api/books",
23 | "applicationUrl": "http://localhost:24141",
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Examples/GettingStarted/README.md:
--------------------------------------------------------------------------------
1 | ## Sample project
2 |
3 | ## Usage
4 |
5 | `dotnet run` to run the project
6 |
7 | You can verify the project is running by checking this endpoint:
8 | `localhost:24141/api/people`
9 |
10 | For further documentation and implementation of a JsonApiDotNetCore application, see the documentation or GitHub page:
11 |
12 | Repository: https://github.com/json-api-dotnet/JsonApiDotNetCore
13 | Documentation: https://www.jsonapi.net
14 |
--------------------------------------------------------------------------------
/src/Examples/GettingStarted/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "DatabaseSettings": {
3 | "ConnectionString": "mongodb://localhost:27017",
4 | "Database": "JsonApiDotNetCoreMongoDbGettingStarted"
5 | },
6 | "Logging": {
7 | "LogLevel": {
8 | "Default": "Warning",
9 | // Include server startup and incoming requests.
10 | "Microsoft.Hosting.Lifetime": "Information",
11 | "Microsoft.AspNetCore.Hosting.Diagnostics": "Information",
12 | "Microsoft.EntityFrameworkCore": "Critical"
13 | }
14 | },
15 | "AllowedHosts": "*"
16 | }
17 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/Controllers/OperationsController.cs:
--------------------------------------------------------------------------------
1 | using JsonApiDotNetCore.AtomicOperations;
2 | using JsonApiDotNetCore.Configuration;
3 | using JsonApiDotNetCore.Controllers;
4 | using JsonApiDotNetCore.Middleware;
5 | using JsonApiDotNetCore.Resources;
6 |
7 | namespace JsonApiDotNetCoreMongoDbExample.Controllers;
8 |
9 | public sealed class OperationsController(
10 | IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IOperationsProcessor processor, IJsonApiRequest request,
11 | ITargetedFields targetedFields, IAtomicOperationFilter operationFilter)
12 | : JsonApiOperationsController(options, resourceGraph, loggerFactory, processor, request, targetedFields, operationFilter);
13 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using JetBrains.Annotations;
3 | using JsonApiDotNetCore.Configuration;
4 | using JsonApiDotNetCore.Middleware;
5 | using JsonApiDotNetCore.Queries.Expressions;
6 | using JsonApiDotNetCore.Resources;
7 | using JsonApiDotNetCoreMongoDbExample.Models;
8 |
9 | namespace JsonApiDotNetCoreMongoDbExample.Definitions;
10 |
11 | [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
12 | public sealed class TodoItemDefinition(IResourceGraph resourceGraph, TimeProvider timeProvider)
13 | : JsonApiResourceDefinition(resourceGraph)
14 | {
15 | private readonly TimeProvider _timeProvider = timeProvider;
16 |
17 | public override SortExpression OnApplySort(SortExpression? existingSort)
18 | {
19 | return existingSort ?? GetDefaultSortOrder();
20 | }
21 |
22 | private SortExpression GetDefaultSortOrder()
23 | {
24 | return CreateSortExpressionFromLambda([
25 | (todoItem => todoItem.Priority, ListSortDirection.Ascending),
26 | (todoItem => todoItem.LastModifiedAt, ListSortDirection.Descending)
27 | ]);
28 | }
29 |
30 | public override Task OnWritingAsync(TodoItem resource, WriteOperationKind writeOperation, CancellationToken cancellationToken)
31 | {
32 | if (writeOperation == WriteOperationKind.CreateResource)
33 | {
34 | resource.CreatedAt = _timeProvider.GetUtcNow();
35 | }
36 | else if (writeOperation == WriteOperationKind.UpdateResource)
37 | {
38 | resource.LastModifiedAt = _timeProvider.GetUtcNow();
39 | }
40 |
41 | return Task.CompletedTask;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net9.0;net8.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/Models/TodoItem.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 | using JetBrains.Annotations;
3 | using JsonApiDotNetCore.MongoDb.Resources;
4 | using JsonApiDotNetCore.Resources.Annotations;
5 |
6 | namespace JsonApiDotNetCoreMongoDbExample.Models;
7 |
8 | [UsedImplicitly(ImplicitUseTargetFlags.Members)]
9 | [Resource]
10 | public sealed class TodoItem : HexStringMongoIdentifiable
11 | {
12 | [Attr]
13 | public string Description { get; set; } = null!;
14 |
15 | [Attr]
16 | [Required]
17 | public TodoItemPriority? Priority { get; set; }
18 |
19 | [Attr]
20 | public long? DurationInHours { get; set; }
21 |
22 | [Attr(Capabilities = AttrCapabilities.AllowFilter | AttrCapabilities.AllowSort | AttrCapabilities.AllowView)]
23 | public DateTimeOffset CreatedAt { get; set; }
24 |
25 | [Attr(PublicName = "modifiedAt", Capabilities = AttrCapabilities.AllowFilter | AttrCapabilities.AllowSort | AttrCapabilities.AllowView)]
26 | public DateTimeOffset? LastModifiedAt { get; set; }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/Models/TodoItemPriority.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 |
3 | namespace JsonApiDotNetCoreMongoDbExample.Models;
4 |
5 | [UsedImplicitly(ImplicitUseTargetFlags.Members)]
6 | public enum TodoItemPriority
7 | {
8 | High = 1,
9 | Medium = 2,
10 | Low = 3
11 | }
12 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using System.Text.Json.Serialization;
3 | using JsonApiDotNetCore.Configuration;
4 | using JsonApiDotNetCore.MongoDb.Configuration;
5 | using JsonApiDotNetCore.MongoDb.Repositories;
6 | using JsonApiDotNetCore.Repositories;
7 | using Microsoft.Extensions.DependencyInjection.Extensions;
8 | using MongoDB.Driver;
9 |
10 | [assembly: ExcludeFromCodeCoverage]
11 |
12 | WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
13 |
14 | // Add services to the container.
15 |
16 | builder.Services.TryAddSingleton(TimeProvider.System);
17 |
18 | builder.Services.TryAddSingleton(_ =>
19 | {
20 | var client = new MongoClient(builder.Configuration.GetValue("DatabaseSettings:ConnectionString"));
21 | return client.GetDatabase(builder.Configuration.GetValue("DatabaseSettings:Database"));
22 | });
23 |
24 | builder.Services.TryAddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
25 | builder.Services.TryAddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
26 | builder.Services.TryAddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
27 |
28 | builder.Services.AddJsonApi(ConfigureJsonApiOptions, facade => facade.AddCurrentAssembly());
29 | builder.Services.AddJsonApiMongoDb();
30 |
31 | WebApplication app = builder.Build();
32 |
33 | // Configure the HTTP request pipeline.
34 |
35 | app.UseRouting();
36 | app.UseJsonApi();
37 | app.MapControllers();
38 |
39 | await app.RunAsync();
40 |
41 | static void ConfigureJsonApiOptions(JsonApiOptions options)
42 | {
43 | options.Namespace = "api";
44 | options.UseRelativeLinks = true;
45 | options.IncludeTotalResourceCount = true;
46 | options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
47 | #if DEBUG
48 | options.IncludeExceptionStackTraceInErrors = true;
49 | options.IncludeRequestBodyInErrors = true;
50 | options.SerializerOptions.WriteIndented = true;
51 | #endif
52 | }
53 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:24140",
8 | "sslPort": 44340
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "api/todoItems",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "Kestrel": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "api/todoItems",
24 | "applicationUrl": "https://localhost:44340;http://localhost:24140",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Examples/JsonApiDotNetCoreMongoDbExample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "DatabaseSettings": {
3 | "ConnectionString": "mongodb://localhost:27017",
4 | "Database": "JsonApiDotNetCoreMongoDbExample"
5 | },
6 | "Logging": {
7 | "LogLevel": {
8 | "Default": "Warning",
9 | // Include server startup and incoming requests.
10 | "Microsoft.Hosting.Lifetime": "Information",
11 | "Microsoft.AspNetCore.Hosting.Diagnostics": "Information",
12 | "Microsoft.EntityFrameworkCore": "Critical"
13 | }
14 | },
15 | "AllowedHosts": "*"
16 | }
17 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 | using JsonApiDotNetCore.AtomicOperations;
3 | using JsonApiDotNetCore.MongoDb.Repositories;
4 |
5 | namespace JsonApiDotNetCore.MongoDb.AtomicOperations;
6 |
7 | ///
8 | [PublicAPI]
9 | public sealed class MongoTransaction : IOperationsTransaction
10 | {
11 | private readonly IMongoDataAccess _mongoDataAccess;
12 | private readonly bool _ownsTransaction;
13 |
14 | ///
15 | public string TransactionId => _mongoDataAccess.TransactionId!;
16 |
17 | public MongoTransaction(IMongoDataAccess mongoDataAccess, bool ownsTransaction)
18 | {
19 | ArgumentNullException.ThrowIfNull(mongoDataAccess);
20 |
21 | _mongoDataAccess = mongoDataAccess;
22 | _ownsTransaction = ownsTransaction;
23 | }
24 |
25 | ///
26 | public Task BeforeProcessOperationAsync(CancellationToken cancellationToken)
27 | {
28 | return Task.CompletedTask;
29 | }
30 |
31 | ///
32 | public Task AfterProcessOperationAsync(CancellationToken cancellationToken)
33 | {
34 | return Task.CompletedTask;
35 | }
36 |
37 | ///
38 | public async Task CommitAsync(CancellationToken cancellationToken)
39 | {
40 | if (_ownsTransaction && _mongoDataAccess.ActiveSession != null)
41 | {
42 | await _mongoDataAccess.ActiveSession.CommitTransactionAsync(cancellationToken);
43 | }
44 | }
45 |
46 | ///
47 | public async ValueTask DisposeAsync()
48 | {
49 | if (_ownsTransaction)
50 | {
51 | await _mongoDataAccess.DisposeAsync();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransactionFactory.cs:
--------------------------------------------------------------------------------
1 | using JsonApiDotNetCore.AtomicOperations;
2 | using JsonApiDotNetCore.MongoDb.Repositories;
3 |
4 | namespace JsonApiDotNetCore.MongoDb.AtomicOperations;
5 |
6 | ///
7 | /// Provides transaction support for atomic:operation requests using MongoDB.
8 | ///
9 | public sealed class MongoTransactionFactory : IOperationsTransactionFactory
10 | {
11 | private readonly IMongoDataAccess _mongoDataAccess;
12 |
13 | public MongoTransactionFactory(IMongoDataAccess mongoDataAccess)
14 | {
15 | ArgumentNullException.ThrowIfNull(mongoDataAccess);
16 |
17 | _mongoDataAccess = mongoDataAccess;
18 | }
19 |
20 | ///
21 | public async Task BeginTransactionAsync(CancellationToken cancellationToken)
22 | {
23 | bool transactionCreated = await CreateOrJoinTransactionAsync(cancellationToken);
24 | return new MongoTransaction(_mongoDataAccess, transactionCreated);
25 | }
26 |
27 | private async Task CreateOrJoinTransactionAsync(CancellationToken cancellationToken)
28 | {
29 | _mongoDataAccess.ActiveSession ??= await _mongoDataAccess.MongoDatabase.Client.StartSessionAsync(cancellationToken: cancellationToken);
30 |
31 | if (_mongoDataAccess.ActiveSession.IsInTransaction)
32 | {
33 | return false;
34 | }
35 |
36 | _mongoDataAccess.ActiveSession.StartTransaction();
37 | return true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Configuration/ResourceGraphExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using JsonApiDotNetCore.Configuration;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Metadata;
5 | using Microsoft.EntityFrameworkCore.Metadata.Builders;
6 | using MongoDB.Bson.Serialization.Attributes;
7 |
8 | namespace JsonApiDotNetCore.MongoDb.Configuration;
9 |
10 | internal static class ResourceGraphExtensions
11 | {
12 | public static IReadOnlyModel ToEntityModel(this IResourceGraph resourceGraph)
13 | {
14 | ArgumentNullException.ThrowIfNull(resourceGraph);
15 |
16 | var modelBuilder = new ModelBuilder();
17 |
18 | foreach (ResourceType resourceType in resourceGraph.GetResourceTypes())
19 | {
20 | IncludeResourceType(resourceType, modelBuilder);
21 | }
22 |
23 | return modelBuilder.Model;
24 | }
25 |
26 | private static void IncludeResourceType(ResourceType resourceType, ModelBuilder builder)
27 | {
28 | EntityTypeBuilder entityTypeBuilder = builder.Entity(resourceType.ClrType);
29 |
30 | foreach (PropertyInfo property in resourceType.ClrType.GetProperties().Where(property => !IsIgnored(property)))
31 | {
32 | entityTypeBuilder.Property(property.PropertyType, property.Name);
33 | }
34 | }
35 |
36 | private static bool IsIgnored(PropertyInfo property)
37 | {
38 | return property.GetCustomAttribute() != null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using JetBrains.Annotations;
2 | using JsonApiDotNetCore.AtomicOperations;
3 | using JsonApiDotNetCore.Configuration;
4 | using JsonApiDotNetCore.MongoDb.AtomicOperations;
5 | using JsonApiDotNetCore.MongoDb.Queries;
6 | using JsonApiDotNetCore.MongoDb.Repositories;
7 | using JsonApiDotNetCore.Queries;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.DependencyInjection.Extensions;
10 |
11 | namespace JsonApiDotNetCore.MongoDb.Configuration;
12 |
13 | public static class ServiceCollectionExtensions
14 | {
15 | ///
16 | /// Expands JsonApiDotNetCore configuration for usage with MongoDB.
17 | ///
18 | [PublicAPI]
19 | public static IServiceCollection AddJsonApiMongoDb(this IServiceCollection services)
20 | {
21 | ArgumentNullException.ThrowIfNull(services);
22 |
23 | services.TryAddSingleton(serviceProvider =>
24 | {
25 | var resourceGraph = serviceProvider.GetRequiredService();
26 | return resourceGraph.ToEntityModel();
27 | });
28 |
29 | services.TryAddScoped();
30 |
31 | // Replace the built-in implementations from JsonApiDotNetCore.
32 | services.AddScoped();
33 | services.AddScoped();
34 |
35 | return services;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Errors/AttributeComparisonInFilterNotSupportedException.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using JetBrains.Annotations;
3 | using JsonApiDotNetCore.Errors;
4 | using JsonApiDotNetCore.Serialization.Objects;
5 |
6 | namespace JsonApiDotNetCore.MongoDb.Errors;
7 |
8 | ///
9 | /// The error that is thrown when a filter compares two attributes. This is not supported by MongoDB.Driver. See
10 | /// https://jira.mongodb.org/browse/CSHARP-1592.
11 | ///
12 | [PublicAPI]
13 | public sealed class AttributeComparisonInFilterNotSupportedException()
14 | : JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
15 | {
16 | Title = "Comparing attributes against each other is not supported when using MongoDB."
17 | });
18 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Errors/UnsupportedRelationshipException.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using JetBrains.Annotations;
3 | using JsonApiDotNetCore.Errors;
4 | using JsonApiDotNetCore.Serialization.Objects;
5 |
6 | namespace JsonApiDotNetCore.MongoDb.Errors;
7 |
8 | ///
9 | /// The error that is thrown when the user attempts to fetch, create or update a relationship.
10 | ///
11 | [PublicAPI]
12 | public sealed class UnsupportedRelationshipException()
13 | : JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
14 | {
15 | Title = "Relationships are not supported when using MongoDB."
16 | });
17 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | true
5 | true
6 |
7 |
8 |
9 |
10 |
11 | jsonapi;json:api;dotnet;asp.net;rest;web-api;MongoDB
12 | MongoDB persistence for JsonApiDotNetCore, which is a framework for building JSON:API compliant REST APIs using ASP.NET Core.
13 | json-api-dotnet
14 | https://www.jsonapi.net/
15 | MIT
16 | false
17 | See https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/releases.
18 | package-icon.png
19 | PackageReadme.md
20 | true
21 | embedded
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/PolyfillCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.ObjectModel;
2 |
3 | namespace JsonApiDotNetCore.MongoDb;
4 |
5 | // These methods provide polyfills for lower .NET versions.
6 | internal static class PolyfillCollectionExtensions
7 | {
8 | public static IReadOnlySet AsReadOnly(this HashSet source)
9 | {
10 | return new ReadOnlySet(source);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("TestBuildingBlocks")]
4 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Queries/HideRelationshipsSparseFieldSetCache.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 | using JsonApiDotNetCore.Configuration;
3 | using JsonApiDotNetCore.MongoDb.Resources;
4 | using JsonApiDotNetCore.Queries;
5 | using JsonApiDotNetCore.Resources;
6 | using JsonApiDotNetCore.Resources.Annotations;
7 |
8 | namespace JsonApiDotNetCore.MongoDb.Queries;
9 |
10 | ///
11 | public sealed class HideRelationshipsSparseFieldSetCache : ISparseFieldSetCache
12 | {
13 | private readonly SparseFieldSetCache _innerCache;
14 |
15 | public HideRelationshipsSparseFieldSetCache(IEnumerable constraintProviders,
16 | IResourceDefinitionAccessor resourceDefinitionAccessor)
17 | {
18 | ArgumentNullException.ThrowIfNull(constraintProviders);
19 | ArgumentNullException.ThrowIfNull(resourceDefinitionAccessor);
20 |
21 | _innerCache = new SparseFieldSetCache(constraintProviders, resourceDefinitionAccessor);
22 | }
23 |
24 | ///
25 | public IImmutableSet GetSparseFieldSetForQuery(ResourceType resourceType)
26 | {
27 | ArgumentNullException.ThrowIfNull(resourceType);
28 |
29 | return _innerCache.GetSparseFieldSetForQuery(resourceType);
30 | }
31 |
32 | ///
33 | public IImmutableSet GetIdAttributeSetForRelationshipQuery(ResourceType resourceType)
34 | {
35 | ArgumentNullException.ThrowIfNull(resourceType);
36 |
37 | return _innerCache.GetIdAttributeSetForRelationshipQuery(resourceType);
38 | }
39 |
40 | ///
41 | public IImmutableSet GetSparseFieldSetForSerializer(ResourceType resourceType)
42 | {
43 | ArgumentNullException.ThrowIfNull(resourceType);
44 |
45 | IImmutableSet fieldSet = _innerCache.GetSparseFieldSetForSerializer(resourceType);
46 |
47 | return resourceType.ClrType.IsAssignableTo(typeof(IMongoIdentifiable)) ? RemoveRelationships(fieldSet) : fieldSet;
48 | }
49 |
50 | private static IImmutableSet RemoveRelationships(IImmutableSet fieldSet)
51 | {
52 | ResourceFieldAttribute[] relationships = fieldSet.Where(field => field is RelationshipAttribute).ToArray();
53 | return fieldSet.Except(relationships);
54 | }
55 |
56 | ///
57 | public void Reset()
58 | {
59 | _innerCache.Reset();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Repositories/IMongoDataAccess.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Metadata;
2 | using MongoDB.Driver;
3 |
4 | namespace JsonApiDotNetCore.MongoDb.Repositories;
5 |
6 | ///
7 | /// Provides access to the MongoDB Driver and the optionally active session.
8 | ///
9 | public interface IMongoDataAccess : IAsyncDisposable
10 | {
11 | ///
12 | /// Provides access to the entity model, which is built at startup.
13 | ///
14 | IReadOnlyModel EntityModel { get; }
15 |
16 | ///
17 | /// Provides access to the underlying MongoDB database, which data changes can be applied on.
18 | ///
19 | IMongoDatabase MongoDatabase { get; }
20 |
21 | ///
22 | /// Provides access to the active session, if any.
23 | ///
24 | IClientSessionHandle? ActiveSession { get; set; }
25 |
26 | ///
27 | /// Identifies the current transaction, if any.
28 | ///
29 | string? TransactionId { get; }
30 | }
31 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Repositories/MongoDataAccess.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Metadata;
2 | using MongoDB.Driver;
3 |
4 | namespace JsonApiDotNetCore.MongoDb.Repositories;
5 |
6 | ///
7 | public sealed class MongoDataAccess : IMongoDataAccess
8 | {
9 | ///
10 | public IReadOnlyModel EntityModel { get; }
11 |
12 | ///
13 | public IMongoDatabase MongoDatabase { get; }
14 |
15 | ///
16 | public IClientSessionHandle? ActiveSession { get; set; }
17 |
18 | ///
19 | public string? TransactionId => ActiveSession is { IsInTransaction: true } ? ActiveSession.GetHashCode().ToString() : null;
20 |
21 | public MongoDataAccess(IReadOnlyModel entityModel, IMongoDatabase mongoDatabase)
22 | {
23 | ArgumentNullException.ThrowIfNull(entityModel);
24 | ArgumentNullException.ThrowIfNull(mongoDatabase);
25 |
26 | EntityModel = entityModel;
27 | MongoDatabase = mongoDatabase;
28 | }
29 |
30 | ///
31 | public async ValueTask DisposeAsync()
32 | {
33 | if (ActiveSession != null)
34 | {
35 | if (ActiveSession.IsInTransaction)
36 | {
37 | await ActiveSession.AbortTransactionAsync();
38 | }
39 |
40 | ActiveSession.Dispose();
41 | ActiveSession = null;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/JsonApiDotNetCore.MongoDb/Repositories/MongoQueryExpressionValidator.cs:
--------------------------------------------------------------------------------
1 | using JsonApiDotNetCore.Configuration;
2 | using JsonApiDotNetCore.MongoDb.Errors;
3 | using JsonApiDotNetCore.Queries;
4 | using JsonApiDotNetCore.Queries.Expressions;
5 | using JsonApiDotNetCore.Resources.Annotations;
6 |
7 | namespace JsonApiDotNetCore.MongoDb.Repositories;
8 |
9 | internal sealed class MongoQueryExpressionValidator : QueryExpressionRewriter